Compare commits

...

10 Commits

Author SHA1 Message Date
Matt Walsh
bef42a3da2 6.1.4 2025-08-11 22:35:18 -05:00
Matt Walsh
13ff0317e6 fix nighttime icons on extended forecast close #134 2025-08-11 22:35:03 -05:00
Matt Walsh
5cc85840a9 6.1.3 2025-08-11 22:15:28 -05:00
Matt Walsh
190e50e2f3 add debugging information to forecast info box 2025-08-11 22:15:16 -05:00
Matt Walsh
aa7ac64827 6.1.2 2025-08-10 20:56:50 -05:00
Matt Walsh
2ab737d5a5 update dependencies 2025-08-10 20:56:40 -05:00
Matt Walsh
ecf0999675 6.1.1 2025-08-10 20:21:44 -05:00
Matt Walsh
6a49b7b6ce fix Washington DC truncated on regional maps close #133 2025-08-10 20:20:53 -05:00
Matt Walsh
5ffff03db9 6.1.0 2025-08-10 20:05:16 -05:00
Matt Walsh
c8a25e5d9a Integrate no-data icon close #94 #128 2025-08-10 20:05:07 -05:00
23 changed files with 1404 additions and 918 deletions

View File

@@ -11,4 +11,4 @@ Please do not report issues with api.weather.gov being down. It's a new service
Please include:
* Web browser and OS
* Location for which you are viewing a forecast
* Forecast Information text block from the very bottom of the web page

View File

@@ -335,6 +335,10 @@ Before reporting an issue or requesting a feature please consider that this is n
Note: not all units are converted to metric, if selected. Some text-based products such as warnings are simple text strings provided from the national weather service and thus have baked-in units such as "gusts up to 60 mph." These values will not be converted.
## The full moon icon is broken
This is a known problem with the Ws4kp as it ages. It was a problem with the [actual Weatherstar hardware](https://youtu.be/rcUwlZ4pqh0?feature=shared&t=116) as well.
## Related Projects
Not retro enough? Try the [Weatherstar 3000+](https://github.com/netbymatt/ws3kp)

View File

@@ -84,8 +84,8 @@
"lat": 29.7633,
"lon": -95.3633,
"point": {
"x": 65,
"y": 97,
"x": 63,
"y": 95,
"wfo": "HGX"
}
},
@@ -230,7 +230,7 @@
}
},
{
"city": "Washington DC",
"city": "Washington",
"lat": 38.8951,
"lon": -77.0364,
"point": {
@@ -274,7 +274,7 @@
"lat": 61.2181,
"lon": -149.9003,
"point": {
"x": 125,
"x": 143,
"y": 236,
"wfo": "AER"
}
@@ -734,8 +734,8 @@
"lat": 42.9956,
"lon": -71.4548,
"point": {
"x": 42,
"y": 21,
"x": 38,
"y": 20,
"wfo": "GYX"
}
},
@@ -884,8 +884,8 @@
"lat": 43.6615,
"lon": -70.2553,
"point": {
"x": 76,
"y": 59,
"x": 72,
"y": 58,
"wfo": "GYX"
}
},

View File

@@ -115,7 +115,7 @@
"lon": -82.5329
},
{
"city": "Washington DC",
"city": "Washington",
"lat": 38.8951,
"lon": -77.0364
},

1378
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ws4kp",
"version": "6.0.1",
"version": "6.1.4",
"description": "Welcome to the WeatherStar 4000+ project page!",
"main": "index.mjs",
"type": "module",
@@ -56,6 +56,6 @@
"dotenv": "^17.0.1",
"ejs": "^3.1.5",
"express": "^5.1.0",
"metar-taf-parser": "^6.1.2"
"metar-taf-parser": "^9.0.0"
}
}

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

View File

@@ -145,6 +145,8 @@ const init = async () => {
document.querySelector('#spanStationId').innerHTML = '';
document.querySelector('#spanRadarId').innerHTML = '';
document.querySelector('#spanZoneId').innerHTML = '';
document.querySelector('#spanOfficeId').innerHTML = '';
document.querySelector('#spanGridPoint').innerHTML = '';
localStorage.removeItem('play');
postMessage('navButton', 'play');

View File

@@ -9,11 +9,19 @@ class Almanac extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Almanac', true);
// occasional degraded moon icon
this.iconPaths = {
Full: imageName(Math.random() > 0.995 ? 'Degraded' : 'Full'),
Last: imageName('Last'),
New: imageName('New'),
First: imageName('First'),
};
// preload the moon images
preloadImg(imageName('Full'));
preloadImg(imageName('Last'));
preloadImg(imageName('New'));
preloadImg(imageName('First'));
preloadImg(this.iconPaths.Full);
preloadImg(this.iconPaths.Last);
preloadImg(this.iconPaths.New);
preloadImg(this.iconPaths.First);
this.timing.totalScreens = 1;
}
@@ -142,7 +150,7 @@ class Almanac extends WeatherDisplay {
fill.date = date;
fill.type = MoonPhase.phase;
fill.icon = { type: 'img', src: imageName(MoonPhase.phase) };
fill.icon = { type: 'img', src: this.iconPaths[MoonPhase.phase] };
return this.fillTemplate('day', fill);
});
@@ -169,6 +177,8 @@ const imageName = (type) => {
switch (type) {
case 'Full':
return 'images/icons/moon-phases/Full-Moon.gif';
case 'Degraded':
return 'images/icons/moon-phases/Full-Moon-Degraded.gif';
case 'Last':
return 'images/icons/moon-phases/Last-Quarter.gif';
case 'New':

View File

@@ -85,7 +85,6 @@ class CurrentWeather extends WeatherDisplay {
const requiredFields = [
{ name: 'temperature', check: (props) => props.temperature?.value === null, required: true },
{ name: 'textDescription', check: (props) => props.textDescription === null || props.textDescription === '', required: true },
{ name: 'icon', check: (props) => props.icon === null, required: true },
{ name: 'windSpeed', check: (props) => props.windSpeed?.value === null, required: false },
{ name: 'dewpoint', check: (props) => props.dewpoint?.value === null, required: false },
{ name: 'barometricPressure', check: (props) => props.barometricPressure?.value === null, required: false },

View File

@@ -137,10 +137,6 @@ const parse = (fullForecast, forecastUrl) => {
}
// get the object to modify/populate
const fDay = forecast[destIndex];
// high temperature will always be last in the source array so it will overwrite the low values assigned below
fDay.icon = getLargeIcon(period.icon);
fDay.text = shortenExtendedForecastText(period.shortForecast);
fDay.dayName = dates[destIndex];
// preload the icon
preloadImg(fDay.icon);
@@ -148,6 +144,9 @@ const parse = (fullForecast, forecastUrl) => {
if (period.isDaytime) {
// day time is the high temperature
fDay.high = period.temperature;
fDay.icon = getLargeIcon(period.icon);
fDay.text = shortenExtendedForecastText(period.shortForecast);
fDay.dayName = dates[destIndex];
// Wait for the corresponding night period to increment
} else {
// low temperature

View File

@@ -13,7 +13,7 @@ const largeIcon = (link, _isNightTime) => {
} catch (error) {
console.warn(`largeIcon: ${error.message}`);
// Return a fallback icon to prevent downstream errors
return addPath(_isNightTime ? 'Clear.gif' : 'Sunny.gif');
return addPath(`No-Data.gif?${conditionIcon}${isNightTime ? '-n' : ''}`);
}
// find the icon
@@ -169,7 +169,7 @@ const largeIcon = (link, _isNightTime) => {
default: {
console.warn(`Unknown weather condition '${conditionIcon}' from ${link}; using fallback icon`);
// Return a reasonable fallback instead of false to prevent downstream errors
return addPath(isNightTime ? 'Clear.gif' : 'Sunny.gif');
return addPath(`No-Data.gif?${conditionIcon}${isNightTime ? '-n' : ''}`);
}
}
};

View File

@@ -111,7 +111,7 @@ const getWeather = async (latLon, haveDataCallback) => {
weatherParameters.stations = stations.features;
// update the main process for display purposes
populateWeatherParameters(weatherParameters);
populateWeatherParameters(weatherParameters, point.properties);
// reset the scroll
postMessage({ type: 'current-weather-scroll', method: 'reload' });
@@ -753,12 +753,14 @@ const registerProgress = (_progress) => {
progress = _progress;
};
const populateWeatherParameters = (params) => {
const populateWeatherParameters = (params, point) => {
document.querySelector('#spanCity').innerHTML = `${params.city}, `;
document.querySelector('#spanState').innerHTML = params.state;
document.querySelector('#spanStationId').innerHTML = params.stationId;
document.querySelector('#spanRadarId').innerHTML = params.radarId;
document.querySelector('#spanZoneId').innerHTML = params.zoneId;
document.querySelector('#spanOfficeId').innerHTML = point.cwa;
document.querySelector('#spanGridPoint').innerHTML = `${point.gridX},${point.gridY}`;
};
const latLonReceived = (data, haveDataCallback) => {

View File

@@ -94,7 +94,7 @@ var en = {
TS: "thunderstorm",
},
Error: {
prefix: "An error occured. Error code n°",
prefix: "An error occurred. Error code n°",
},
ErrorCode: {
AirportNotFound: "The airport was not found for this message.",
@@ -136,11 +136,13 @@ var en = {
TS: "thunderstorm",
UP: "unknown precipitation",
VA: "volcanic ash",
NSW: 'no significant weather'
},
Remark: {
ALQDS: "all quadrants",
AO1: "automated stations without a precipitation discriminator",
AO2: "automated station with a precipitation discriminator",
AO2A: "automated station with a precipitation discriminator (augmented)",
BASED: "based",
Barometer: [
"Increase, then decrease",
@@ -156,7 +158,7 @@ var en = {
Ceiling: {
Height: "ceiling varying between {0} and {1} feet",
Second: {
Location: "ceiling of {0} feet mesured by a second sensor located at {1}",
Location: "ceiling of {0} feet measured by a second sensor located at {1}",
},
},
DSNT: "distant",
@@ -192,6 +194,11 @@ var en = {
LGT: "light",
LTG: "lightning",
MOD: "moderate",
Next: {
Forecast: {
By: "next forecast by {0}, {1}:{2}Z"
},
},
NXT: "next",
ON: "on",
Obscuration: "{0} layer at {1} feet composed of {2}",
@@ -223,7 +230,7 @@ var en = {
},
Second: {
Location: {
Visibility: "visibility of {0} SM mesured by a second sensor located at {1}",
Visibility: "visibility of {0} SM measured by a second sensor located at {1}",
},
},
Sector: {

File diff suppressed because one or more lines are too long

View File

@@ -1053,10 +1053,18 @@ class Locale {
months(length, format = false) {
return listStuff(this, length, months, () => {
// Workaround for "ja" locale: formatToParts does not label all parts of the month
// as "month" and for this locale there is no difference between "format" and "non-format".
// As such, just use format() instead of formatToParts() and take the whole string
const monthSpecialCase = this.intl === "ja" || this.intl.startsWith("ja-");
format &= !monthSpecialCase;
const intl = format ? { month: length, day: "numeric" } : { month: length },
formatStr = format ? "format" : "standalone";
if (!this.monthsCache[formatStr][length]) {
this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
const mapper = !monthSpecialCase
? (dt) => this.extract(dt, intl, "month")
: (dt) => this.dtFormatter(dt, intl).format();
this.monthsCache[formatStr][length] = mapMonths(mapper);
}
return this.monthsCache[formatStr][length];
});
@@ -2040,10 +2048,24 @@ function parseMillis(fraction) {
}
}
function roundTo(number, digits, towardZero = false) {
const factor = 10 ** digits,
rounder = towardZero ? Math.trunc : Math.round;
return rounder(number * factor) / factor;
function roundTo(number, digits, rounding = "round") {
const factor = 10 ** digits;
switch (rounding) {
case "expand":
return number > 0
? Math.ceil(number * factor) / factor
: Math.floor(number * factor) / factor;
case "trunc":
return Math.trunc(number * factor) / factor;
case "round":
return Math.round(number * factor) / factor;
case "floor":
return Math.floor(number * factor) / factor;
case "ceil":
return Math.ceil(number * factor) / factor;
default:
throw new RangeError(`Value rounding ${rounding} is out of range`);
}
}
// DATE BASICS
@@ -2151,7 +2173,7 @@ function signedOffset(offHourStr, offMinuteStr) {
function asNumber(value) {
const numericValue = Number(value);
if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue))
if (typeof value === "boolean" || value === "" || !Number.isFinite(numericValue))
throw new InvalidArgumentError(`Invalid unit value ${value}`);
return numericValue;
}
@@ -2410,8 +2432,12 @@ class Formatter {
for (let i = 0; i < fmt.length; i++) {
const c = fmt.charAt(i);
if (c === "'") {
if (currentFull.length > 0) {
splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
// turn '' into a literal signal quote instead of just skipping the empty literal
if (currentFull.length > 0 || bracketed) {
splits.push({
literal: bracketed || /^\s+$/.test(currentFull),
val: currentFull === "" ? "'" : currentFull,
});
}
current = null;
currentFull = "";
@@ -2475,7 +2501,7 @@ class Formatter {
return this.dtFormatter(dt, opts).resolvedOptions();
}
num(n, p = 0) {
num(n, p = 0, signDisplay = undefined) {
// we get some perf out of doing this here, annoyingly
if (this.opts.forceSimple) {
return padStart(n, p);
@@ -2486,6 +2512,9 @@ class Formatter {
if (p > 0) {
opts.padTo = p;
}
if (signDisplay) {
opts.signDisplay = signDisplay;
}
return this.loc.numberFormatter(opts).format(n);
}
@@ -2721,32 +2750,44 @@ class Formatter {
}
formatDurationFromString(dur, fmt) {
const invertLargest = this.opts.signMode === "negativeLargestOnly" ? -1 : 1;
const tokenToField = (token) => {
switch (token[0]) {
case "S":
return "millisecond";
return "milliseconds";
case "s":
return "second";
return "seconds";
case "m":
return "minute";
return "minutes";
case "h":
return "hour";
return "hours";
case "d":
return "day";
return "days";
case "w":
return "week";
return "weeks";
case "M":
return "month";
return "months";
case "y":
return "year";
return "years";
default:
return null;
}
},
tokenToString = (lildur) => (token) => {
tokenToString = (lildur, info) => (token) => {
const mapped = tokenToField(token);
if (mapped) {
return this.num(lildur.get(mapped), token.length);
const inversionFactor =
info.isNegativeDuration && mapped !== info.largestUnit ? invertLargest : 1;
let signDisplay;
if (this.opts.signMode === "negativeLargestOnly" && mapped !== info.largestUnit) {
signDisplay = "never";
} else if (this.opts.signMode === "all") {
signDisplay = "always";
} else {
// "auto" and "negative" are the same, but "auto" has better support
signDisplay = "auto";
}
return this.num(lildur.get(mapped) * inversionFactor, token.length, signDisplay);
} else {
return token;
}
@@ -2756,8 +2797,14 @@ class Formatter {
(found, { literal, val }) => (literal ? found : found.concat(val)),
[]
),
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t));
return stringifyTokens(tokens, tokenToString(collapsed));
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t)),
durationInfo = {
isNegativeDuration: collapsed < 0,
// this relies on "collapsed" being based on "shiftTo", which builds up the object
// in order
largestUnit: Object.keys(collapsed.values)[0],
};
return stringifyTokens(tokens, tokenToString(collapsed, durationInfo));
}
}
@@ -2818,11 +2865,11 @@ function simpleParse(...keys) {
}
// ISO and SQL parsing
const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;
const offsetRegex = /(?:([Zz])|([+-]\d\d)(?::?(\d\d))?)/;
const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
const isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`);
const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`);
const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
@@ -3537,9 +3584,13 @@ class Duration {
* @param {string} fmt - the format string
* @param {Object} opts - options
* @param {boolean} [opts.floor=true] - floor numerical values
* @param {'negative'|'all'|'negativeLargestOnly'} [opts.signMode=negative] - How to handle signs
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("y d s") //=> "1 6 2"
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("yy dd sss") //=> "01 06 002"
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("M S") //=> "12 518402000"
* @example Duration.fromObject({ days: 6, seconds: 2 }).toFormat("d s", { signMode: "all" }) //=> "+6 +2"
* @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "all" }) //=> "-6 -2"
* @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "negativeLargestOnly" }) //=> "-6 2"
* @return {string}
*/
toFormat(fmt, opts = {}) {
@@ -3559,21 +3610,25 @@ class Duration {
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
* @param {Object} opts - Formatting options. Accepts the same keys as the options parameter of the native `Intl.NumberFormat` constructor, as well as `listStyle`.
* @param {string} [opts.listStyle='narrow'] - How to format the merged list. Corresponds to the `style` property of the options parameter of the native `Intl.ListFormat` constructor.
* @param {boolean} [opts.showZeros=true] - Show all units previously used by the duration even if they are zero
* @example
* ```js
* var dur = Duration.fromObject({ days: 1, hours: 5, minutes: 6 })
* dur.toHuman() //=> '1 day, 5 hours, 6 minutes'
* dur.toHuman({ listStyle: "long" }) //=> '1 day, 5 hours, and 6 minutes'
* dur.toHuman({ unitDisplay: "short" }) //=> '1 day, 5 hr, 6 min'
* var dur = Duration.fromObject({ months: 1, weeks: 0, hours: 5, minutes: 6 })
* dur.toHuman() //=> '1 month, 0 weeks, 5 hours, 6 minutes'
* dur.toHuman({ listStyle: "long" }) //=> '1 month, 0 weeks, 5 hours, and 6 minutes'
* dur.toHuman({ unitDisplay: "short" }) //=> '1 mth, 0 wks, 5 hr, 6 min'
* dur.toHuman({ showZeros: false }) //=> '1 month, 5 hours, 6 minutes'
* ```
*/
toHuman(opts = {}) {
if (!this.isValid) return INVALID$2;
const showZeros = opts.showZeros !== false;
const l = orderedUnits$1
.map((unit) => {
const val = this.values[unit];
if (isUndefined(val)) {
if (isUndefined(val) || (val === 0 && !showZeros)) {
return null;
}
return this.loc
@@ -3933,6 +3988,17 @@ class Duration {
return clone$1(this, { values: negated }, true);
}
/**
* Removes all units with values equal to 0 from this Duration.
* @example Duration.fromObject({ years: 2, days: 0, hours: 0, minutes: 0 }).removeZeros().toObject() //=> { years: 2 }
* @return {Duration}
*/
removeZeros() {
if (!this.isValid) return this;
const vals = removeZeroes(this.values);
return clone$1(this, { values: vals }, true);
}
/**
* Get the years.
* @type {number}
@@ -4243,7 +4309,8 @@ class Interval {
}
/**
* Returns the end of the Interval
* Returns the end of the Interval. This is the first instant which is not part of the interval
* (Interval is half-open).
* @type {DateTime}
*/
get end() {
@@ -5674,21 +5741,22 @@ function toTechFormat(dt, format, allowZ = true) {
: null;
}
function toISODate(o, extended) {
function toISODate(o, extended, precision) {
const longFormat = o.c.year > 9999 || o.c.year < 0;
let c = "";
if (longFormat && o.c.year >= 0) c += "+";
c += padStart(o.c.year, longFormat ? 6 : 4);
if (precision === "year") return c;
if (extended) {
c += "-";
c += padStart(o.c.month);
if (precision === "month") return c;
c += "-";
c += padStart(o.c.day);
} else {
c += padStart(o.c.month);
c += padStart(o.c.day);
if (precision === "month") return c;
}
c += padStart(o.c.day);
return c;
}
@@ -5698,26 +5766,39 @@ function toISOTime(
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone
extendedZone,
precision
) {
let c = padStart(o.c.hour);
if (extended) {
c += ":";
c += padStart(o.c.minute);
if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
c += ":";
}
} else {
c += padStart(o.c.minute);
}
if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
c += padStart(o.c.second);
if (o.c.millisecond !== 0 || !suppressMilliseconds) {
c += ".";
c += padStart(o.c.millisecond, 3);
}
let showSeconds = !suppressSeconds || o.c.millisecond !== 0 || o.c.second !== 0,
c = "";
switch (precision) {
case "day":
case "month":
case "year":
break;
default:
c += padStart(o.c.hour);
if (precision === "hour") break;
if (extended) {
c += ":";
c += padStart(o.c.minute);
if (precision === "minute") break;
if (showSeconds) {
c += ":";
c += padStart(o.c.second);
}
} else {
c += padStart(o.c.minute);
if (precision === "minute") break;
if (showSeconds) {
c += padStart(o.c.second);
}
}
if (precision === "second") break;
if (showSeconds && (!suppressMilliseconds || o.c.millisecond !== 0)) {
c += ".";
c += padStart(o.c.millisecond, 3);
}
}
if (includeOffset) {
@@ -5909,8 +5990,9 @@ function quickDT(obj, opts) {
function diffRelative(start, end, opts) {
const round = isUndefined(opts.round) ? true : opts.round,
rounding = isUndefined(opts.rounding) ? "trunc" : opts.rounding,
format = (c, unit) => {
c = roundTo(c, round || opts.calendary ? 0 : 2, true);
c = roundTo(c, round || opts.calendary ? 0 : 2, opts.calendary ? "round" : rounding);
const formatter = end.loc.clone(opts).relFormatter(opts);
return formatter.format(c, unit);
},
@@ -7289,10 +7371,13 @@ class DateTime {
* @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
* @param {boolean} [opts.extendedZone=false] - add the time zone format extension
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'years', 'months', 'days', 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
* @example DateTime.utc(1983, 5, 25).toISO() //=> '1982-05-25T00:00:00.000Z'
* @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00'
* @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335'
* @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400'
* @example DateTime.now().toISO({ precision: 'day' }) //=> '2017-04-22Z'
* @example DateTime.now().toISO({ precision: 'minute' }) //=> '2017-04-22T20:47Z'
* @return {string|null}
*/
toISO({
@@ -7301,16 +7386,26 @@ class DateTime {
suppressMilliseconds = false,
includeOffset = true,
extendedZone = false,
precision = "milliseconds",
} = {}) {
if (!this.isValid) {
return null;
}
precision = normalizeUnit(precision);
const ext = format === "extended";
let c = toISODate(this, ext);
c += "T";
c += toISOTime(this, ext, suppressSeconds, suppressMilliseconds, includeOffset, extendedZone);
let c = toISODate(this, ext, precision);
if (orderedUnits.indexOf(precision) >= 3) c += "T";
c += toISOTime(
this,
ext,
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone,
precision
);
return c;
}
@@ -7318,16 +7413,17 @@ class DateTime {
* Returns an ISO 8601-compliant string representation of this DateTime's date component
* @param {Object} opts - options
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='day'] - truncate output to desired precision: 'years', 'months', or 'days'.
* @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25'
* @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525'
* @example DateTime.utc(1982, 5, 25).toISODate({ precision: 'month' }) //=> '1982-05'
* @return {string|null}
*/
toISODate({ format = "extended" } = {}) {
toISODate({ format = "extended", precision = "day" } = {}) {
if (!this.isValid) {
return null;
}
return toISODate(this, format === "extended");
return toISODate(this, format === "extended", normalizeUnit(precision));
}
/**
@@ -7348,10 +7444,12 @@ class DateTime {
* @param {boolean} [opts.extendedZone=true] - add the time zone format extension
* @param {boolean} [opts.includePrefix=false] - include the `T` prefix
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime() //=> '07:34:19.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34, seconds: 0, milliseconds: 0 }).toISOTime({ suppressSeconds: true }) //=> '07:34Z'
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ format: 'basic' }) //=> '073419.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ includePrefix: true }) //=> 'T07:34:19.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34, second: 56 }).toISOTime({ precision: 'minute' }) //=> '07:34Z'
* @return {string}
*/
toISOTime({
@@ -7361,12 +7459,14 @@ class DateTime {
includePrefix = false,
extendedZone = false,
format = "extended",
precision = "milliseconds",
} = {}) {
if (!this.isValid) {
return null;
}
let c = includePrefix ? "T" : "";
precision = normalizeUnit(precision);
let c = includePrefix && orderedUnits.indexOf(precision) >= 3 ? "T" : "";
return (
c +
toISOTime(
@@ -7375,7 +7475,8 @@ class DateTime {
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone
extendedZone,
precision
)
);
}
@@ -7653,12 +7754,13 @@ class DateTime {
/**
* Returns a string representation of a this time relative to now, such as "in two days". Can only internationalize if your
* platform supports Intl.RelativeTimeFormat. Rounds down by default.
* platform supports Intl.RelativeTimeFormat. Rounds towards zero by default.
* @param {Object} options - options that affect the output
* @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now.
* @param {string} [options.style="long"] - the style of units, must be "long", "short", or "narrow"
* @param {string|string[]} options.unit - use a specific unit or array of units; if omitted, or an array, the method will pick the best unit. Use an array or one of "years", "quarters", "months", "weeks", "days", "hours", "minutes", or "seconds"
* @param {boolean} [options.round=true] - whether to round the numbers in the output.
* @param {string} [options.rounding="trunc"] - rounding method to use when rounding the numbers in the output. Can be "trunc" (toward zero), "expand" (away from zero), "round", "floor", or "ceil".
* @param {number} [options.padding=0] - padding in milliseconds. This allows you to round up the result if it fits inside the threshold. Don't use in combination with {round: false} because the decimal output will include the padding.
* @param {string} options.locale - override the locale of this DateTime
* @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this
@@ -8025,7 +8127,7 @@ function friendlyDateTime(dateTimeish) {
}
}
const VERSION = "3.6.1";
const VERSION = "3.7.1";
export { DateTime, Duration, FixedOffsetZone, IANAZone, Info, Interval, InvalidZone, Settings, SystemZone, VERSION, Zone };
//# sourceMappingURL=luxon.js.map

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,7 @@ const tester = async (location, testPage) => {
// run all the locations
for (let i = 0; i < LOCATIONS.length; i += 1) {
const location = LOCATIONS[i];
console.log(location);
console.log(`${i + 1}/${LOCATIONS.length} ${location}`);
// eslint-disable-next-line no-await-in-loop
await tester(location, page);
}

View File

@@ -191,6 +191,8 @@
Station Id: <span id="spanStationId"></span><br />
Radar Id: <span id="spanRadarId"></span><br />
Zone Id: <span id="spanZoneId"></span><br />
Office Id: <span id="spanOfficeId"></span><br />
Grid X,Y: <span id="spanGridPoint"></span><br />
Music: <span id="musicTrack">Not playing</span><br />
Ws4kp Version: <span><%- version %></span>
</div>
@@ -198,4 +200,4 @@
</body>
</html>
</html>