Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Before contributing code, I strongly recommend reviewing my [architecture docume
2. Clone your fork: `git clone https://github.com/[your-username]/calendar-card-pro.git`
3. Install dependencies: `npm install`
4. Start development mode: `npm run dev`
5. The compiled card will be available in `dist/calendar-card-pro.js`
5. The compiled card will be available in `dist/calendar-card-pro-dev.js`
6. For testing in Home Assistant, follow the [testing instructions](#testing-in-home-assistant)

## Branch Structure
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ Configure how event times and locations are displayed:
show_time: true # Show event start/end times
show_single_allday_time: false # Hide time for single-day all-day events
time_24h: false # Use 12-hour format (AM/PM)
two_digit_hours: false # Use 2 digits in hours
show_end_time: true # Show event end time
time_font_size: '12px'
time_color: 'var(--secondary-text-color)'
Expand Down Expand Up @@ -1204,6 +1205,7 @@ These examples demonstrate how Calendar Card Pro can be customized to match any
| `show_time` | boolean | `true` | Whether to show event times |
| `show_single_allday_time` | boolean | `true` | Whether to show time display for all-day single-day events |
| `time_24h` | boolean | `System` | Whether to use 24-hour time format (auto-detects from HA) |
| `two_digit_hours` | boolean | `false` | Whether to use 2 digits in hours |
| `show_end_time` | boolean | `true` | Whether to show event end times |
| `time_icon_size` | string | `14px` | Clock icon size (replaces time_location_icon_size) |
| `time_font_size` | string | `12px` | Event time font size |
Expand Down Expand Up @@ -1342,6 +1344,8 @@ start_date: '2025-07-01'
days_to_show: 10
compact_events_to_show: 10
language: en
time_24h: true
two_digit_hours: false

# Header
title: 📅 Full Calendar Demo
Expand Down Expand Up @@ -1373,7 +1377,6 @@ month_color: '#baf1ff'
show_past_events: false
event_font_size: 14px
event_color: '#baf1ff'
time_24h: true
show_end_time: true
time_font_size: 12px
time_color: '#baf1ff'
Expand Down
1 change: 1 addition & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const DEFAULT_CONFIG: Types.Config = {
show_time: true,
show_single_allday_time: true,
time_24h: 'system',
two_digit_hours: false,
show_end_time: true,
time_font_size: '12px',
time_color: 'var(--secondary-text-color)',
Expand Down
1 change: 1 addition & 0 deletions src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export interface Config {
show_time: boolean;
show_single_allday_time: boolean;
time_24h: boolean | 'system';
two_digit_hours: boolean;
show_end_time: boolean;
time_font_size: string;
time_color: string;
Expand Down
1 change: 1 addition & 0 deletions src/rendering/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ export class CalendarCardProEditor extends LitElement {
{ value: 'true', label: this._getTranslation('24h') },
{ value: 'false', label: this._getTranslation('12h') },
])}
${this.addBooleanField('two_digit_hours', this._getTranslation('two_digit_hours'))}
`,
)}

Expand Down
1 change: 1 addition & 0 deletions src/translations/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"custom": "Custom",
"12h": "12-hour",
"24h": "24-hour",
"two_digit_hours": "2 digit hours",

"appearance_layout": "Appearance & Layout",
"title_styling": "Title Styling",
Expand Down
1 change: 1 addition & 0 deletions src/translations/languages/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"custom": "Egendefinert",
"12h": "12-timer",
"24h": "24-timer",
"two_digit_hours": "2 sifre i timer",

"appearance_layout": "Utseende og layout",
"title_styling": "Tittelformatering",
Expand Down
51 changes: 32 additions & 19 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export function formatEventTime(
translations,
useNativeFormatting,
use24h,
config.two_digit_hours,
hass,
),
);
Expand All @@ -93,6 +94,7 @@ export function formatEventTime(
config.show_end_time,
useNativeFormatting,
use24h,
config.two_digit_hours,
hass,
),
);
Expand All @@ -103,8 +105,7 @@ export function formatEventTime(
* Uses dayjs for consistent, localized relative time formatting
*
* @param event Calendar event to generate countdown for
* @param hass Home Assistant instance (used to extract language)
* @param config Card configuration options
* @param language Language to use
* @returns Countdown string or null if event is past or empty day
*/
export function getCountdownString(
Expand Down Expand Up @@ -204,19 +205,27 @@ export function getLocalDateKey(date: Date): string {
*
* @param date Date object to format
* @param use24h Whether to use 24-hour format
* @param twoDigitHours Whether to use 2 digits in hours
* @returns Formatted time string
*/
export function formatTime(date: Date, use24h = true): string {
export function formatTime(date: Date, use24h = true, twoDigitHours = false): string {
let hours = date.getHours();
const minutes = date.getMinutes();

if (!use24h) {
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
return `${hours}:${minutes.toString().padStart(2, '0')} ${ampm}`;
return `${twoDigitHours ? pad(hours) : hours}:${pad(minutes)} ${ampm}`;
}

return `${hours}:${minutes.toString().padStart(2, '0')}`;
return `${twoDigitHours ? pad(hours) : hours}:${pad(minutes)}`;
}

/**
* Pad with 0 if only one digit.
*/
function pad(n: number): string {
return n.toString().padStart(2, '0');
}

/**
Expand All @@ -238,9 +247,7 @@ export function getISOWeekNumber(date: Date): number {
const yearStart = new Date(d.getFullYear(), 0, 1);

// Calculate full weeks to nearest Thursday
const weekNumber = Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);

return weekNumber;
return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

/**
Expand All @@ -265,9 +272,7 @@ export function getSimpleWeekNumber(date: Date, firstDayOfWeek: number = 0): num
const dayOfWeekOffset = (startOfYear.getDay() - firstDayOfWeek + 7) % 7;

// Calculate week number (adding 1 because we want weeks to start from 1)
const weekNumber = Math.ceil((days + dayOfWeekOffset + 1) / 7);

return weekNumber;
return Math.ceil((days + dayOfWeekOffset + 1) / 7);
}

/**
Expand Down Expand Up @@ -340,7 +345,10 @@ export function getWeekNumber(
* @param startDate Start date of the event
* @param endDate End date of the event
* @param showEndTime Whether to show end time
* @param time24h Whether to use 24-hour format
* @param useNativeFormatting Wheter to use native formatting
* @param use24h Whether to use 24-hour format
* @param twoDigitHours Whether to use 2 digits in hours
* @param hass Home Assistant
* @returns Formatted time string
*/
function formatSingleDayTime(
Expand All @@ -349,6 +357,7 @@ function formatSingleDayTime(
showEndTime: boolean,
useNativeFormatting: boolean,
use24h: boolean = true,
twoDigitHours: boolean = false,
hass?: Types.Hass | null,
): string {
if (useNativeFormatting && hass?.locale) {
Expand All @@ -357,14 +366,14 @@ function formatSingleDayTime(

// Use our formatter with the detected format preference
return showEndTime
? `${formatTime(startDate, use24hFormat)} - ${formatTime(endDate, use24hFormat)}`
: formatTime(startDate, use24hFormat);
? `${formatTime(startDate, use24hFormat, twoDigitHours)} - ${formatTime(endDate, use24hFormat, twoDigitHours)}`
: formatTime(startDate, use24hFormat, twoDigitHours);
}

// For explicit settings, use our formatter with the specified format
return showEndTime
? `${formatTime(startDate, use24h)} - ${formatTime(endDate, use24h)}`
: formatTime(startDate, use24h);
? `${formatTime(startDate, use24h, twoDigitHours)} - ${formatTime(endDate, use24h, twoDigitHours)}`
: formatTime(startDate, use24h, twoDigitHours);
}

/**
Expand All @@ -374,7 +383,10 @@ function formatSingleDayTime(
* @param endDate End date of the event
* @param language Language code for translations
* @param translations Translations object
* @param time24h Whether to use 24-hour format
* @param useNativeFormatting Wheter to use native formatting
* @param use24h Whether to use 24-hour format
* @param twoDigitHours Whether to use 2 digits in hours
* @param hass Home Assistant
* @returns Formatted time string
*/
function formatMultiDayTime(
Expand All @@ -384,6 +396,7 @@ function formatMultiDayTime(
translations: Types.Translations,
useNativeFormatting: boolean,
use24h: boolean = true,
twoDigitHours: boolean = false,
hass?: Types.Hass | null,
): string {
const now = new Date();
Expand All @@ -396,9 +409,9 @@ function formatMultiDayTime(
if (useNativeFormatting && hass?.locale) {
// Use the helper to determine time format preference
const use24hFormat = Helpers.getTimeFormat24h(hass.locale, use24h);
return formatTime(date, use24hFormat);
return formatTime(date, use24hFormat, twoDigitHours);
}
return formatTime(date, use24h);
return formatTime(date, use24h, twoDigitHours);
};

// Format the end time part based on when the event ends
Expand Down