timezone.service.tsβ’3.25 kB
import { Injectable } from '@nestjs/common'
@Injectable()
export class TimezoneService {
// Get list of all IANA timezones supported by Node.js
getAvailableTimezones(): string[] {
return Intl.supportedValuesOf('timeZone')
}
// Get all unique regions from timezones
getRegions(): string[] {
const timezones = this.getAvailableTimezones()
const regions = new Set<string>()
timezones.forEach((tz) => {
const parts = tz.split('/')
if (parts.length >= 2) {
regions.add(parts[0])
}
})
return Array.from(regions).sort()
}
// Get all cities for a specific region
getCitiesInRegion(region: string): string[] {
const timezones = this.getAvailableTimezones()
const cities: string[] = []
timezones.forEach((tz) => {
const parts = tz.split('/')
if (parts.length >= 2 && parts[0] === region) {
// Handle timezones with multiple parts (e.g., America/Argentina/Buenos_Aires)
cities.push(parts.slice(1).join('/'))
}
})
if (cities.length === 0) {
throw new Error(`Invalid region: ${region}`)
}
return cities.sort()
}
// Get current time in a specific timezone
getTimeInTimezone(timezone: string): {
timezone: string
datetime_local: string
datetime_utc: string
timezone_offset: string
timestamp: number
} {
const timezones = this.getAvailableTimezones()
if (!timezones.includes(timezone)) {
throw new Error(`Invalid timezone: ${timezone}`)
}
const now = new Date()
// Get ISO string for the local timezone
// We need to convert the current UTC time to the target timezone's ISO representation
const localFormatter = new Intl.DateTimeFormat('sv-SE', {
timeZone: timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
})
const parts = localFormatter.formatToParts(now)
const year = parts.find((p) => p.type === 'year')?.value
const month = parts.find((p) => p.type === 'month')?.value
const day = parts.find((p) => p.type === 'day')?.value
const hour = parts.find((p) => p.type === 'hour')?.value
const minute = parts.find((p) => p.type === 'minute')?.value
const second = parts.find((p) => p.type === 'second')?.value
// Get ISO string in UTC
const datetime_utc = now.toISOString()
// Calculate timezone offset
// Create a date formatter that gives us offset info
const offsetFormatter = new Intl.DateTimeFormat('en-US', {
timeZone: timezone,
timeZoneName: 'longOffset',
})
const offsetParts = offsetFormatter.formatToParts(now)
const offsetPart = offsetParts.find((p) => p.type === 'timeZoneName')
// Format will be like "GMT-05:00" or "GMT+09:00", we want just "-05:00" or "+09:00"
const timezone_offset = offsetPart?.value.replace('GMT', '') || '+00:00'
// Complete ISO 8601 format with timezone offset
const datetime_local = `${year}-${month}-${day}T${hour}:${minute}:${second}${timezone_offset}`
return {
timezone,
datetime_local,
datetime_utc,
timezone_offset,
timestamp: now.getTime(),
}
}
}