diff --git a/README.md b/README.md index f1c16c2a..c45f66aa 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,12 @@ Credits go to [basmilius](https://github.com/basmilius) for the awesome [weather ## Migrating from v1 to v2 * Configuration property `forecast_days` was renamed to `forecast_rows` to indicate that this attribute does not only work for daily, but also for hourly forecasts. +* Luxon TODO ## FAQ -- [Why don't I see the current day in my weather forecast?](#why-dont-i-see-the-current-day-in-my-weather-forecast) -- [What does the card actually display?](#what-does-the-card-actually-display) +* [Why don't I see the current day in my weather forecast?](#why-dont-i-see-the-current-day-in-my-weather-forecast) +* [What does the card actually display?](#what-does-the-card-actually-display) ### Why don't I see the current day in my weather forecast? @@ -122,10 +123,10 @@ use_browser_time: true | temperature_sensor | string | **Optional** | ID of the temperature sensor entity. Used to show the current temperature based on a sensor value instead of the weather forecast | `''` | | weather_icon_type | `line` \| `fill` | **Optional** | Appearance of the large weather icon | `line` | | animated_icon | boolean | **Optional** | Whether the large weather icon should be animated | `true` | -| forecast_rows | number | **Optional** | The amount of weather forecast rows to show. Depending on `hourly_forecast` each row either corresponds to a day or an hour. | `5` | +| forecast_rows | number | **Optional** | The amount of weather forecast rows to show. Depending on `hourly_forecast` each row either corresponds to a day or an hour | `5` | | locale | string[^2] | **Optional** | Language to use for language specific text. If not provided, falls back to the locale set in HA | `en-GB` | | time_format | `24` \| `12` | **Optional** | Format used to display the time. If not provided, falls back to the time format set in HA | `24` | -| date_pattern | string | **Optional** | Pattern to use for time formatting. If not provided, falls back to the default date formatting of the configured language. See [date-fns](https://date-fns.org/v2.29.3/docs/format) for valid patterns | `P` | +| date_pattern | string | **Optional** | Pattern to use for date formatting. If not provided, falls back to the default date formatting of the configured language. See [luxon](https://moment.github.io/luxon/#/formatting?id=table-of-tokens) for valid patterns | `DDDD` | | hide_today_section | boolean | **Optional** | Hides the cards today section (upper section), containing the large weather icon, clock and current date | `false` | | hide_forecast_section | boolean | **Optional** | Hides the cards forecast section (lower section),containing the weather forecast | `false` | | hide_clock | boolean | **Optional** | Hides the clock from the today section and prominently displays the current temperature instead | `false` | diff --git a/package.json b/package.json index f3fee2dc..b15c65fa 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,9 @@ "dependencies": { "@lit-labs/scoped-registry-mixin": "^1.0.0", "custom-card-helpers": "^1.8.0", - "date-fns": "^2.29.3", "home-assistant-js-websocket": "^8.0.0", "lit": "^2.0.0", - "luxon": "^3.3.0" + "luxon": "^3.4.3" }, "devDependencies": { "@babel/core": "^7.15.0", @@ -28,7 +27,7 @@ "@babel/plugin-proposal-decorators": "^7.14.5", "@rollup/plugin-image": "^2.1.1", "@rollup/plugin-json": "^5.0.0", - "@types/luxon": "^3.3.0", + "@types/luxon": "^3.4.3", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "eslint": "^7.32.0", diff --git a/src/clock-weather-card.ts b/src/clock-weather-card.ts index 478e8dfe..b28681a0 100644 --- a/src/clock-weather-card.ts +++ b/src/clock-weather-card.ts @@ -30,8 +30,6 @@ import { extractMostOccuring, max, min, round, roundDown, roundIfNotNull, roundU import { svg, png } from './images'; import { version } from '../package.json'; import { safeRender } from './helpers'; -import { format, Locale } from 'date-fns'; -import * as locales from 'date-fns/locale'; import { DateTime } from 'luxon'; console.info( @@ -65,16 +63,16 @@ export class ClockWeatherCard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @state() private config!: MergedClockWeatherCardConfig; - @state() private currentDate!: Date; + @state() private currentDate!: DateTime; @state() private forecastSubscriber?: Promise<() => void>; @state() private forecasts?: WeatherForecast[]; constructor() { super(); - this.currentDate = new Date(); - const msToNextMinute = (60 - this.currentDate.getSeconds()) * 1000; - setTimeout(() => setInterval(() => { this.currentDate = new Date() }, 1000 * 60), msToNextMinute); - setTimeout(() => { this.currentDate = new Date() }, msToNextMinute); + this.currentDate = DateTime.now(); + const msToNextMinute = (60 - this.currentDate.second) * 1000; + setTimeout(() => setInterval(() => { this.currentDate = DateTime.now() }, 1000 * 60), msToNextMinute); + setTimeout(() => { this.currentDate = DateTime.now() }, msToNextMinute); } public static getStubConfig(_hass: HomeAssistant, entities: string[], entitiesFallback: string[]): Record { @@ -241,7 +239,7 @@ export class ClockWeatherCard extends LitElement { private renderForecastItem(forecast: MergedWeatherForecast, gradientRange: Rgb[], minTemp: number, maxTemp: number, currentTemp: number | null, hourly: boolean): TemplateResult { const twelveHour = this.getTimeFormat() === '12'; - const displayText = !hourly ? this.localize('day.' + forecast.datetime.getDay()) : this.time(forecast.datetime); + const displayText = !hourly ? this.localize('day.' + forecast.datetime.getDay()) : this.time(DateTime.fromJSDate(forecast.datetime)); const weatherState = forecast.condition === 'pouring' ? 'raindrops' : forecast.condition === 'rainy' ? 'raindrop' : forecast.condition; const weatherIcon = this.toIcon(weatherState, 'fill', true, 'static'); const tempUnit = this.getWeather().attributes.temperature_unit; @@ -429,36 +427,35 @@ export class ClockWeatherCard extends LitElement { return this.config.locale || this.hass.locale?.language || 'en-GB'; } - private getDateFnsLocale(): Locale { - const locale = this.getLocale(); - const localeParts = locale - .replace('_', '-') - .split('-'); - const localeOne = localeParts[0].toLowerCase(); - const localeTwo = localeParts[1]?.toUpperCase() || ''; - const dateFnsLocale = localeOne + localeTwo; - // HA provides en-US as en - if (dateFnsLocale === 'en') { - return locales.enUS; - } - const importedLocale = locales[dateFnsLocale]; - if (!importedLocale) { - console.error('clock-weather-card - Locale not supported: ' + dateFnsLocale); - return locales.enGB; - } - return importedLocale; - } + // private getDateFnsLocale(): Locale { + // const locale = this.getLocale(); + // const localeParts = locale + // .replace('_', '-') + // .split('-'); + // const localeOne = localeParts[0].toLowerCase(); + // const localeTwo = localeParts[1]?.toUpperCase() || ''; + // const dateFnsLocale = localeOne + localeTwo; + // // HA provides en-US as en + // if (dateFnsLocale === 'en') { + // return locales.enUS; + // } + // const importedLocale = locales[dateFnsLocale]; + // if (!importedLocale) { + // console.error('clock-weather-card - Locale not supported: ' + dateFnsLocale); + // return locales.enGB; + // } + // return importedLocale; + // } private date(): string { - const zonedDate = this.toZonedDate(this.currentDate); - const weekday = this.localize(`day.${zonedDate.getDay()}`); - const date = format(zonedDate, this.config.date_pattern, { locale: this.getDateFnsLocale() }); - return`${weekday}, ${date}` + return this.toZonedDate(this.currentDate) + .setLocale(this.getLocale()) + .toFormat(this.config.date_pattern); } - private time(date: Date = this.currentDate): string { - const withTimeZone = this.toZonedDate(date); - return format(withTimeZone, this.getTimeFormat() === '24' ? 'HH:mm' : 'h:mm aa'); + private time(date: DateTime = this.currentDate): string { + return this.toZonedDate(date) + .toFormat(this.getTimeFormat() === '24' ? 'HH:mm' : 'h:mm aa'); } private getIconAnimationKind(): 'static' | 'animated' { @@ -544,15 +541,16 @@ export class ClockWeatherCard extends LitElement { .slice(0, maxRowsCount); } - private toZonedDate(date: Date): Date { + private toZonedDate(date: DateTime): DateTime { if (this.config.use_browser_time) return date; - const timeZone = this.hass?.config?.time_zone - const withTimeZone = DateTime.fromJSDate(date).setZone(timeZone); + const timeZone = this.hass?.config?.time_zone; + const withTimeZone = date.setZone(timeZone); if (!withTimeZone.isValid) { console.error(`clock-weather-card - Time Zone [${timeZone}] not supported. Falling back to browser time.`); return date; } - return new Date(withTimeZone.year, withTimeZone.month - 1, withTimeZone.day, withTimeZone.hour, withTimeZone.minute, withTimeZone.second, withTimeZone.millisecond); + + return date; } private calculateAverageForecast(forecasts: WeatherForecast[]): MergedWeatherForecast { @@ -616,7 +614,7 @@ export class ClockWeatherCard extends LitElement { } private supportsFeature(feature: WeatherEntityFeature): boolean { - return (this.getWeather().attributes.supported_features! & feature) !== 0 + return (this.getWeather().attributes.supported_features & feature) !== 0 } } diff --git a/src/types.ts b/src/types.ts index b9fe2e91..85cedecb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,7 +75,7 @@ export type WeatherForecast = { } export type MergedWeatherForecast = { - datetime: Date; + datetime: Date; // TODO to DateTime? condition: string; temperature: number; precipitation: number; diff --git a/yarn.lock b/yarn.lock index 0b63a28d..76efc398 100644 --- a/yarn.lock +++ b/yarn.lock @@ -468,10 +468,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/luxon@^3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.0.tgz#a61043a62c0a72696c73a0a305c544c96501e006" - integrity sha512-uKRI5QORDnrGFYgcdAVnHvEIvEZ8noTpP/Bg+HeUzZghwinDlIS87DEenV5r1YoOF9G4x600YsUXLWZ19rmTmg== +"@types/luxon@^3.4.3": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.2.tgz#f6e3524c2486b949a4db445e85d93c8e9886dfe2" + integrity sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ== "@types/node@*": version "12.7.2" @@ -813,11 +813,6 @@ custom-card-helpers@^1.8.0: superstruct "^0.15.3" typescript "^4.5.4" -date-fns@^2.29.3: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== - debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1823,10 +1818,10 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -luxon@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.3.0.tgz#d73ab5b5d2b49a461c47cedbc7e73309b4805b48" - integrity sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg== +luxon@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.3.tgz#8ddf0358a9492267ffec6a13675fbaab5551315d" + integrity sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg== magic-string@^0.25.2: version "0.25.7"