@jmruthers/pace-core 0.5.184 → 0.5.186
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +60 -1
- package/core-usage-manifest.json +312 -0
- package/dist/{DataTable-QAB34V6K.js → DataTable-IX2NBUTP.js} +6 -6
- package/dist/{DataTable-Bz8ffqyA.d.ts → DataTable-Z9NLVJh0.d.ts} +1 -1
- package/dist/{index-Bl--n7-T.d.ts → PublicPageProvider-DIzEzwKl.d.ts} +23 -10
- package/dist/{UnifiedAuthProvider-7F6T4B6K.js → UnifiedAuthProvider-A4BCQRJY.js} +4 -2
- package/dist/{UnifiedAuthProvider-F86d7dSi.d.ts → UnifiedAuthProvider-BG0AL5eE.d.ts} +2 -1
- package/dist/{api-ROMBCNKU.js → api-BMFCXVQX.js} +2 -2
- package/dist/{chunk-RA3JUFMW.js → chunk-445GEP27.js} +154 -4
- package/dist/{chunk-RA3JUFMW.js.map → chunk-445GEP27.js.map} +1 -1
- package/dist/{chunk-W22JP75J.js → chunk-DAGICKHT.js} +9 -7
- package/dist/chunk-DAGICKHT.js.map +1 -0
- package/dist/{chunk-FUEYYMX5.js → chunk-FXFJRTKI.js} +24 -3
- package/dist/chunk-FXFJRTKI.js.map +1 -0
- package/dist/{chunk-CSOFYHAG.js → chunk-GRIQLQ52.js} +374 -60
- package/dist/chunk-GRIQLQ52.js.map +1 -0
- package/dist/{chunk-NQPMQGS2.js → chunk-HDCUMOOI.js} +497 -399
- package/dist/chunk-HDCUMOOI.js.map +1 -0
- package/dist/chunk-HESYZWZW.js +388 -0
- package/dist/chunk-HESYZWZW.js.map +1 -0
- package/dist/{chunk-QUVSNGIP.js → chunk-HGPQUCBC.js} +34 -9
- package/dist/{chunk-QUVSNGIP.js.map → chunk-HGPQUCBC.js.map} +1 -1
- package/dist/{chunk-PWAHJW4G.js → chunk-OALXJH4Y.js} +86 -33
- package/dist/chunk-OALXJH4Y.js.map +1 -0
- package/dist/{chunk-MI7HBHN3.js → chunk-TC7D3CR3.js} +89 -9
- package/dist/chunk-TC7D3CR3.js.map +1 -0
- package/dist/chunk-THRPYOFK.js +215 -0
- package/dist/chunk-THRPYOFK.js.map +1 -0
- package/dist/{chunk-M7W4CP3M.js → chunk-U6WNSFX5.js} +2 -1
- package/dist/chunk-U6WNSFX5.js.map +1 -0
- package/dist/{chunk-UHNYIBXL.js → chunk-UQWSHFVX.js} +1 -1
- package/dist/chunk-UQWSHFVX.js.map +1 -0
- package/dist/{chunk-QCDXODCA.js → chunk-XAUHJD3L.js} +2 -2
- package/dist/components.d.ts +182 -6
- package/dist/components.js +157 -11
- package/dist/components.js.map +1 -1
- package/dist/{database.generated-CBmg2950.d.ts → database.generated-DI89OQeI.d.ts} +63 -9
- package/dist/eslint-rules/pace-core-compliance.cjs +406 -0
- package/dist/{file-reference-D06mEEWW.d.ts → file-reference-PRTSLxKx.d.ts} +10 -1
- package/dist/hooks.d.ts +52 -15
- package/dist/hooks.js +12 -22
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +82 -18
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +206 -15
- package/dist/rbac/index.js +28 -6
- package/dist/timezone-_pgH8qrY.d.ts +530 -0
- package/dist/{types-_x1f4QBF.d.ts → types-DUyCRSTj.d.ts} +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-JJczomYq.d.ts → usePublicRouteParams-D71QLlg4.d.ts} +114 -3
- package/dist/utils.d.ts +110 -152
- package/dist/utils.js +128 -138
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +60 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/Logger.md +178 -0
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +5 -5
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +54 -0
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +18 -2
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +30 -0
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +85 -0
- package/docs/api/interfaces/DatabaseIssue.md +41 -0
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +6 -6
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +48 -8
- package/docs/api/interfaces/FileUploadProps.md +46 -13
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +9 -9
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +62 -0
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +36 -23
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +52 -0
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +4 -4
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +7 -7
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +5 -5
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/RuntimeComplianceResult.md +55 -0
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +41 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseFormDialogOptions.md +62 -0
- package/docs/api/interfaces/UseFormDialogReturn.md +117 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +746 -50
- package/docs/api-reference/components.md +26 -12
- package/docs/api-reference/hooks.md +111 -0
- package/docs/api-reference/rpc-functions.md +1 -1
- package/docs/api-reference/utilities.md +184 -0
- package/docs/getting-started/installation-guide.md +75 -16
- package/docs/getting-started/quick-start.md +61 -11
- package/docs/implementation-guides/authentication.md +88 -12
- package/docs/implementation-guides/file-reference-system.md +26 -3
- package/docs/implementation-guides/file-upload-storage.md +30 -1
- package/docs/rbac/README.md +1 -0
- package/docs/rbac/compliance/compliance-guide.md +544 -0
- package/docs/rbac/getting-started.md +158 -33
- package/docs/standards/pace-core-compliance.md +432 -0
- package/eslint-config-pace-core.cjs +93 -0
- package/package.json +15 -3
- package/scripts/analyze-bundle.js +232 -0
- package/scripts/build-css.js +56 -0
- package/scripts/build-docs-incremental.js +1015 -0
- package/scripts/check-pace-core-compliance.cjs +2353 -0
- package/scripts/check-pace-core-compliance.js +512 -0
- package/scripts/generate-docs.js +157 -0
- package/scripts/setup-build-cache.js +73 -0
- package/scripts/utils/command-runner.js +131 -0
- package/scripts/utils/env.js +33 -0
- package/scripts/utils/index.js +10 -0
- package/scripts/utils/logger.js +88 -0
- package/scripts/utils/path-helpers.js +37 -0
- package/scripts/validate-formats.js +133 -0
- package/scripts/validate-master.js +155 -0
- package/scripts/validate-pre-publish.js +140 -0
- package/scripts/validate-theme.js +142 -0
- package/src/components/Calendar/Calendar.tsx +8 -1
- package/src/components/Card/Card.tsx +47 -8
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +314 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +126 -0
- package/src/components/DatePickerWithTimezone/README.md +135 -0
- package/src/components/DatePickerWithTimezone/index.ts +10 -0
- package/src/components/DateTimeField/DateTimeField.test.tsx +358 -0
- package/src/components/DateTimeField/DateTimeField.tsx +232 -0
- package/src/components/DateTimeField/README.md +148 -0
- package/src/components/DateTimeField/index.ts +10 -0
- package/src/components/FileUpload/FileUpload.test.tsx +2 -0
- package/src/components/FileUpload/FileUpload.tsx +10 -1
- package/src/components/Header/Header.test.tsx +47 -18
- package/src/components/Header/Header.tsx +22 -7
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +29 -20
- package/src/components/PaceAppLayout/README.md +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +37 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +146 -5
- package/src/components/index.ts +8 -0
- package/src/eslint-rules/pace-core-compliance.cjs +406 -0
- package/src/eslint-rules/pace-core-compliance.js +640 -0
- package/src/hooks/__tests__/useFormDialog.test.ts +478 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useFileReference.test.ts +2 -0
- package/src/hooks/useFormDialog.ts +147 -0
- package/src/hooks/usePreventTabReload.ts +106 -0
- package/src/hooks/useSecureDataAccess.ts +2 -2
- package/src/index.ts +27 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +6 -5
- package/src/providers/services/UnifiedAuthProvider.tsx +24 -3
- package/src/rbac/__tests__/rbac-role-isolation.test.ts +456 -0
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +3 -0
- package/src/rbac/compliance/database-validator.ts +165 -0
- package/src/rbac/compliance/index.ts +38 -0
- package/src/rbac/compliance/quick-fix-suggestions.ts +209 -0
- package/src/rbac/compliance/runtime-compliance.ts +77 -0
- package/src/rbac/compliance/setup-validator.ts +131 -0
- package/src/rbac/components/PagePermissionGuard.tsx +8 -64
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +35 -21
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/errors.ts +11 -0
- package/src/rbac/hooks/useRoleManagement.ts +292 -12
- package/src/rbac/index.ts +30 -0
- package/src/services/OrganisationService.ts +4 -0
- package/src/styles/core.css +5 -5
- package/src/types/database.generated.ts +63 -9
- package/src/types/file-reference.ts +9 -0
- package/src/utils/__tests__/timezone.test.ts +345 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +60 -4
- package/src/utils/file-reference/index.ts +13 -2
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +167 -0
- package/src/utils/formatting/formatting.ts +179 -0
- package/src/utils/index.ts +27 -1
- package/src/utils/location/index.ts +16 -0
- package/src/utils/location/location.test.ts +286 -0
- package/src/utils/location/location.ts +175 -0
- package/src/utils/security/secureDataAccess.ts +1 -1
- package/src/utils/storage/helpers.ts +68 -0
- package/src/utils/timezone/index.ts +17 -0
- package/src/utils/timezone/timezone.test.ts +349 -0
- package/src/utils/timezone/timezone.ts +281 -0
- package/dist/chunk-CSOFYHAG.js.map +0 -1
- package/dist/chunk-FUEYYMX5.js.map +0 -1
- package/dist/chunk-HKIT6O7W.js +0 -198
- package/dist/chunk-HKIT6O7W.js.map +0 -1
- package/dist/chunk-KUEN3HFB.js +0 -94
- package/dist/chunk-KUEN3HFB.js.map +0 -1
- package/dist/chunk-M7W4CP3M.js.map +0 -1
- package/dist/chunk-MI7HBHN3.js.map +0 -1
- package/dist/chunk-NQPMQGS2.js.map +0 -1
- package/dist/chunk-PWAHJW4G.js.map +0 -1
- package/dist/chunk-UHNYIBXL.js.map +0 -1
- package/dist/chunk-W22JP75J.js.map +0 -1
- package/dist/formatting-5wETwiGF.d.ts +0 -162
- /package/dist/{DataTable-QAB34V6K.js.map → DataTable-IX2NBUTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-7F6T4B6K.js.map → UnifiedAuthProvider-A4BCQRJY.js.map} +0 -0
- /package/dist/{api-ROMBCNKU.js.map → api-BMFCXVQX.js.map} +0 -0
- /package/dist/{chunk-QCDXODCA.js.map → chunk-XAUHJD3L.js.map} +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Timezone Utilities
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Utils/Timezone
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive timezone conversion and formatting utilities using date-fns-tz and native Intl APIs.
|
|
8
|
+
* Provides functions for timezone-aware date operations, conversions, and formatting.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Format dates in specific timezones
|
|
12
|
+
* - Get timezone abbreviations
|
|
13
|
+
* - Convert between UTC and timezone local times
|
|
14
|
+
* - Round dates to nearest minutes
|
|
15
|
+
* - Calculate timezone differences
|
|
16
|
+
* - Get user's browser timezone
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { toZonedTime, fromZonedTime, formatInTimeZone, getUserTimeZone } from '@jmruthers/pace-core/utils/timezone';
|
|
21
|
+
*
|
|
22
|
+
* // Convert UTC to local timezone
|
|
23
|
+
* const utcDate = new Date('2024-01-15T10:00:00Z');
|
|
24
|
+
* const localDate = toZonedTime(utcDate, 'America/New_York');
|
|
25
|
+
*
|
|
26
|
+
* // Convert local time to UTC
|
|
27
|
+
* const localInput = new Date(2024, 0, 15, 10, 0);
|
|
28
|
+
* const utcDate = fromZonedTime(localInput, 'America/New_York');
|
|
29
|
+
*
|
|
30
|
+
* // Format with timezone
|
|
31
|
+
* const formatted = formatInTimeZone(utcDate, 'America/New_York', 'MMM dd, yyyy HH:mm');
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { format, parseISO, addMinutes, differenceInHours, isValid } from 'date-fns';
|
|
36
|
+
import { formatInTimeZone as fnsFormatInTimeZone, toZonedTime as fnsToZonedTime, fromZonedTime as fnsFromZonedTime } from 'date-fns-tz';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Format a date in a specific timezone using date-fns format strings
|
|
40
|
+
*
|
|
41
|
+
* @param date - Date to format (Date object, ISO string, or timestamp)
|
|
42
|
+
* @param timeZone - IANA timezone string (e.g., 'America/New_York')
|
|
43
|
+
* @param formatStr - date-fns format string (e.g., 'MMM dd, yyyy HH:mm')
|
|
44
|
+
* @returns Formatted date string or 'Invalid date' on error
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* formatInTimeZone(new Date('2024-01-15T10:00:00Z'), 'America/New_York', 'MMM dd, yyyy HH:mm');
|
|
49
|
+
* // "Jan 15, 2024 05:00"
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function formatInTimeZone(
|
|
53
|
+
date: Date | string | number,
|
|
54
|
+
timeZone: string,
|
|
55
|
+
formatStr: string
|
|
56
|
+
): string {
|
|
57
|
+
try {
|
|
58
|
+
if (!timeZone || typeof timeZone !== 'string') {
|
|
59
|
+
return 'Invalid date';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let dateObj: Date;
|
|
63
|
+
if (typeof date === 'string') {
|
|
64
|
+
dateObj = parseISO(date);
|
|
65
|
+
} else if (typeof date === 'number') {
|
|
66
|
+
dateObj = new Date(date);
|
|
67
|
+
} else {
|
|
68
|
+
dateObj = date;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!isValid(dateObj)) {
|
|
72
|
+
return 'Invalid date';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return fnsFormatInTimeZone(dateObj, timeZone, formatStr);
|
|
76
|
+
} catch {
|
|
77
|
+
return 'Invalid date';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the timezone abbreviation (EST, PST, etc.) for a date in a specific timezone
|
|
83
|
+
*
|
|
84
|
+
* @param date - Date to get abbreviation for
|
|
85
|
+
* @param timeZone - IANA timezone string
|
|
86
|
+
* @returns Timezone abbreviation or timezone name on error
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* getTimezoneAbbreviation(new Date(), 'America/New_York');
|
|
91
|
+
* // "EST" or "EDT" depending on date
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function getTimezoneAbbreviation(date: Date, timeZone: string): string {
|
|
95
|
+
try {
|
|
96
|
+
if (!timeZone || typeof timeZone !== 'string') {
|
|
97
|
+
return timeZone || 'UTC';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!isValid(date)) {
|
|
101
|
+
return timeZone;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
105
|
+
timeZone,
|
|
106
|
+
timeZoneName: 'short'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const parts = formatter.formatToParts(date);
|
|
110
|
+
const timeZoneName = parts.find(part => part.type === 'timeZoneName');
|
|
111
|
+
|
|
112
|
+
return timeZoneName?.value || timeZone;
|
|
113
|
+
} catch {
|
|
114
|
+
return timeZone || 'UTC';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Format time only in a specific timezone
|
|
120
|
+
*
|
|
121
|
+
* @param date - Date to format
|
|
122
|
+
* @param timeZone - IANA timezone string
|
|
123
|
+
* @returns Formatted time string (HH:mm format) or 'Invalid date' on error
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* formatTimeInTimeZone(new Date('2024-01-15T10:00:00Z'), 'America/New_York');
|
|
128
|
+
* // "05:00"
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function formatTimeInTimeZone(date: Date | string, timeZone: string): string {
|
|
132
|
+
return formatInTimeZone(date, timeZone, 'HH:mm');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get the user's local timezone from the browser
|
|
137
|
+
*
|
|
138
|
+
* @returns IANA timezone string (e.g., 'America/New_York')
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const userTz = getUserTimeZone();
|
|
143
|
+
* // "America/New_York" or user's actual timezone
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export function getUserTimeZone(): string {
|
|
147
|
+
try {
|
|
148
|
+
if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
|
|
149
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
150
|
+
}
|
|
151
|
+
return 'UTC';
|
|
152
|
+
} catch {
|
|
153
|
+
return 'UTC';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Convert a UTC date to a specific timezone's local time representation
|
|
159
|
+
*
|
|
160
|
+
* @param date - UTC date to convert
|
|
161
|
+
* @param timezone - IANA timezone string
|
|
162
|
+
* @returns Date object representing local time in the timezone
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* const utcDate = new Date('2024-01-15T10:00:00Z');
|
|
167
|
+
* const localDate = toZonedTime(utcDate, 'America/New_York');
|
|
168
|
+
* // Returns Date object representing 5:00 AM in New York
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
export function toZonedTime(date: Date, timezone: string): Date {
|
|
172
|
+
try {
|
|
173
|
+
if (!timezone || typeof timezone !== 'string') {
|
|
174
|
+
return date;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!isValid(date)) {
|
|
178
|
+
return date;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return fnsToZonedTime(date, timezone);
|
|
182
|
+
} catch {
|
|
183
|
+
return date;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Convert a local time in a specific timezone to UTC
|
|
189
|
+
*
|
|
190
|
+
* @param localDate - Local date in the timezone
|
|
191
|
+
* @param timezone - IANA timezone string
|
|
192
|
+
* @returns Date object in UTC
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* const localDate = new Date(2024, 0, 15, 10, 0); // Jan 15, 2024 10:00 AM local
|
|
197
|
+
* const utcDate = fromZonedTime(localDate, 'America/New_York');
|
|
198
|
+
* // Returns Date object representing 3:00 PM UTC (if EST) or 2:00 PM UTC (if EDT)
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export function fromZonedTime(localDate: Date, timezone: string): Date {
|
|
202
|
+
try {
|
|
203
|
+
if (!timezone || typeof timezone !== 'string') {
|
|
204
|
+
return localDate;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!isValid(localDate)) {
|
|
208
|
+
return localDate;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return fnsFromZonedTime(localDate, timezone);
|
|
212
|
+
} catch {
|
|
213
|
+
return localDate;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Round a date to the nearest X minutes
|
|
219
|
+
*
|
|
220
|
+
* @param date - Date to round
|
|
221
|
+
* @param minutesStep - Number of minutes to round to (default: 5)
|
|
222
|
+
* @returns Rounded date
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* const date = new Date('2024-01-15T10:23:00Z');
|
|
227
|
+
* roundToNearestMinutes(date, 5);
|
|
228
|
+
* // Returns Date object for 10:25:00
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
export function roundToNearestMinutes(date: Date, minutesStep: number = 5): Date {
|
|
232
|
+
try {
|
|
233
|
+
if (!isValid(date)) {
|
|
234
|
+
return date;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (minutesStep <= 0 || !Number.isInteger(minutesStep)) {
|
|
238
|
+
return date;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const minutes = date.getMinutes();
|
|
242
|
+
const roundedMinutes = Math.round(minutes / minutesStep) * minutesStep;
|
|
243
|
+
const diff = roundedMinutes - minutes;
|
|
244
|
+
|
|
245
|
+
return addMinutes(date, diff);
|
|
246
|
+
} catch {
|
|
247
|
+
return date;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Calculate the time difference between two timezones in hours
|
|
253
|
+
*
|
|
254
|
+
* @param fromTimeZone - Source timezone (IANA string)
|
|
255
|
+
* @param toTimeZone - Target timezone (IANA string)
|
|
256
|
+
* @returns Difference in hours (positive if toTimeZone is ahead)
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* getTimeZoneDifference('America/New_York', 'America/Los_Angeles');
|
|
261
|
+
* // -3 (Los Angeles is 3 hours behind New York)
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export function getTimeZoneDifference(fromTimeZone: string, toTimeZone: string): number {
|
|
265
|
+
try {
|
|
266
|
+
if (!fromTimeZone || !toTimeZone || typeof fromTimeZone !== 'string' || typeof toTimeZone !== 'string') {
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const now = new Date();
|
|
271
|
+
const fromDate = toZonedTime(now, fromTimeZone);
|
|
272
|
+
const toDate = toZonedTime(now, toTimeZone);
|
|
273
|
+
|
|
274
|
+
const diff = differenceInHours(toDate, fromDate);
|
|
275
|
+
// Handle NaN case (differenceInHours can return NaN for invalid dates)
|
|
276
|
+
return isNaN(diff) ? 0 : diff;
|
|
277
|
+
} catch {
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|