display last updated timestamp parsed from Excel filename
This commit is contained in:
parent
078050dce6
commit
06ead18b38
2 changed files with 59 additions and 2 deletions
39
main.go
39
main.go
|
|
@ -9,8 +9,11 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
|
@ -36,6 +39,11 @@ type Station struct {
|
|||
Diesel float64 `json:"diesel"`
|
||||
}
|
||||
|
||||
type StationsResponse struct {
|
||||
LastUpdated string `json:"lastUpdated"`
|
||||
Stations []Station `json:"stations"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
|
|
@ -61,9 +69,14 @@ func handleStations(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
resp := StationsResponse{
|
||||
LastUpdated: parseTimestampFromURL(dataURL),
|
||||
Stations: stations,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Cache-Control", "public, max-age=3600")
|
||||
json.NewEncoder(w).Encode(stations)
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
func fetchAndParse() ([]Station, error) {
|
||||
|
|
@ -169,3 +182,27 @@ func parsePrice(s string) float64 {
|
|||
}
|
||||
return v
|
||||
}
|
||||
|
||||
var tsRegex = regexp.MustCompile(`(\d{14})`)
|
||||
|
||||
// parseTimestampFromURL extracts a YYYYMMDDHHmmSS timestamp from the URL
|
||||
// filename and returns it as a human-readable string.
|
||||
func parseTimestampFromURL(rawURL string) string {
|
||||
base := path.Base(rawURL)
|
||||
match := tsRegex.FindString(base)
|
||||
if match == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation("America/Montreal")
|
||||
if err != nil {
|
||||
loc = time.UTC
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation("20060102150405", match, loc)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return t.Format(time.RFC3339)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@
|
|||
.legend-labels { display: flex; justify-content: space-between; font-size: 11px; color: #666; }
|
||||
#stats { margin-top: 8px; font-size: 11px; color: #888; }
|
||||
|
||||
#last-updated {
|
||||
position: fixed; bottom: 8px; left: 56px;
|
||||
background: white; padding: 5px 10px;
|
||||
border-radius: 6px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);
|
||||
z-index: 2000; font-size: 11px; color: #666;
|
||||
}
|
||||
|
||||
/* Colored pin markers */
|
||||
.pin-icon {
|
||||
filter: drop-shadow(0 1px 3px rgba(0,0,0,0.35));
|
||||
|
|
@ -89,6 +96,8 @@
|
|||
<div id="visible-count"></div>
|
||||
</div>
|
||||
|
||||
<div id="last-updated"></div>
|
||||
|
||||
<div id="legend">
|
||||
<h3>Prix régulier (¢/L)</h3>
|
||||
<div class="legend-gradient"></div>
|
||||
|
|
@ -126,10 +135,21 @@
|
|||
|
||||
fetch('/api/stations')
|
||||
.then(r => r.json())
|
||||
.then(stations => {
|
||||
.then(data => {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
const stations = data.stations;
|
||||
allStations = stations;
|
||||
|
||||
// Last updated
|
||||
if (data.lastUpdated) {
|
||||
const d = new Date(data.lastUpdated);
|
||||
document.getElementById('last-updated').textContent =
|
||||
'Dernière mise à jour: ' + d.toLocaleString('fr-CA', {
|
||||
year: 'numeric', month: 'long', day: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit',
|
||||
});
|
||||
}
|
||||
|
||||
const prices = stations.map(s => s.regular).filter(p => p > 0);
|
||||
minPrice = Math.min(...prices);
|
||||
maxPrice = Math.max(...prices);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue