Created
August 24, 2025 07:51
-
-
Save hikaMaeng/bc41eeb35e6e71e5d472b81637b27d33 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
enum class CountryCode(val code:String, val fullName:String) { | |
AD("AD", "Andorra"), | |
AE("AE", "United Arab Emirates"), | |
AF("AF", "Afghanistan"), | |
AL("AL", "Albania"), | |
AM("AM", "Armenia"), | |
AQ("AQ", "Antarctica"), | |
AR("AR", "Argentina"), | |
AS("AS", "Samoa (American)"), | |
AT("AT", "Austria"), | |
AU("AU", "Australia"), | |
AZ("AZ", "Azerbaijan"), | |
BB("BB", "Barbados"), | |
BD("BD", "Bangladesh"), | |
BE("BE", "Belgium"), | |
BG("BG", "Bulgaria"), | |
BM("BM", "Bermuda"), | |
BO("BO", "Bolivia"), | |
BR("BR", "Brazil"), | |
BT("BT", "Bhutan"), | |
BY("BY", "Belarus"), | |
BZ("BZ", "Belize"), | |
CA("CA", "Canada"), | |
CH("CH", "Switzerland"), | |
CI("CI", "Côte d'Ivoire"), | |
CK("CK", "Cook Islands"), | |
CL("CL", "Chile"), | |
CN("CN", "China"), | |
CO("CO", "Colombia"), | |
CR("CR", "Costa Rica"), | |
CU("CU", "Cuba"), | |
CV("CV", "Cape Verde"), | |
CY("CY", "Cyprus"), | |
CZ("CZ", "Czech Republic"), | |
DE("DE", "Germany"), | |
DO("DO", "Dominican Republic"), | |
DZ("DZ", "Algeria"), | |
EC("EC", "Ecuador"), | |
EE("EE", "Estonia"), | |
EG("EG", "Egypt"), | |
EH("EH", "Western Sahara"), | |
ES("ES", "Spain"), | |
FI("FI", "Finland"), | |
FJ("FJ", "Fiji"), | |
FK("FK", "Falkland Islands"), | |
FM("FM", "Micronesia"), | |
FO("FO", "Faroe Islands"), | |
FR("FR", "France"), | |
GB("GB", "Britain (UK)"), | |
GE("GE", "Georgia"), | |
GF("GF", "French Guiana"), | |
GI("GI", "Gibraltar"), | |
GL("GL", "Greenland"), | |
GR("GR", "Greece"), | |
GS("GS", "South Georgia & the South Sandwich Islands"), | |
GT("GT", "Guatemala"), | |
GU("GU", "Guam"), | |
GW("GW", "Guinea-Bissau"), | |
GY("GY", "Guyana"), | |
HK("HK", "Hong Kong"), | |
HN("HN", "Honduras"), | |
HT("HT", "Haiti"), | |
HU("HU", "Hungary"), | |
ID("ID", "Indonesia"), | |
IE("IE", "Ireland"), | |
IL("IL", "Israel"), | |
IN("IN", "India"), | |
IO("IO", "British Indian Ocean Territory"), | |
IQ("IQ", "Iraq"), | |
IR("IR", "Iran"), | |
IT("IT", "Italy"), | |
JM("JM", "Jamaica"), | |
JO("JO", "Jordan"), | |
JP("JP", "Japan"), | |
KE("KE", "Kenya"), | |
KG("KG", "Kyrgyzstan"), | |
KI("KI", "Kiribati"), | |
KP("KP", "Korea (North)"), | |
KR("KR", "Korea (South)"), | |
KZ("KZ", "Kazakhstan"), | |
LB("LB", "Lebanon"), | |
LK("LK", "Sri Lanka"), | |
LR("LR", "Liberia"), | |
LT("LT", "Lithuania"), | |
LV("LV", "Latvia"), | |
LY("LY", "Libya"), | |
MA("MA", "Morocco"), | |
MD("MD", "Moldova"), | |
MH("MH", "Marshall Islands"), | |
MM("MM", "Myanmar (Burma)"), | |
MN("MN", "Mongolia"), | |
MO("MO", "Macau"), | |
MQ("MQ", "Martinique"), | |
MT("MT", "Malta"), | |
MU("MU", "Mauritius"), | |
MV("MV", "Maldives"), | |
MX("MX", "Mexico"), | |
MY("MY", "Malaysia"), | |
MZ("MZ", "Mozambique"), | |
NA("NA", "Namibia"), | |
NC("NC", "New Caledonia"), | |
NF("NF", "Norfolk Island"), | |
NG("NG", "Nigeria"), | |
NI("NI", "Nicaragua"), | |
NP("NP", "Nepal"), | |
NR("NR", "Nauru"), | |
NU("NU", "Niue"), | |
NZ("NZ", "New Zealand"), | |
PA("PA", "Panama"), | |
PE("PE", "Peru"), | |
PF("PF", "French Polynesia"), | |
PG("PG", "Papua New Guinea"), | |
PH("PH", "Philippines"), | |
PK("PK", "Pakistan"), | |
PL("PL", "Poland"), | |
PM("PM", "St Pierre & Miquelon"), | |
PN("PN", "Pitcairn"), | |
PR("PR", "Puerto Rico"), | |
PS("PS", "Palestine"), | |
PT("PT", "Portugal"), | |
PW("PW", "Palau"), | |
PY("PY", "Paraguay"), | |
QA("QA", "Qatar"), | |
RO("RO", "Romania"), | |
RS("RS", "Serbia"), | |
RU("RU", "Russia"), | |
SA("SA", "Saudi Arabia"), | |
SB("SB", "Solomon Islands"), | |
SD("SD", "Sudan"), | |
SG("SG", "Singapore"), | |
SR("SR", "Suriname"), | |
SS("SS", "South Sudan"), | |
ST("ST", "Sao Tome & Principe"), | |
SV("SV", "El Salvador"), | |
SY("SY", "Syria"), | |
TC("TC", "Turks & Caicos Is"), | |
TD("TD", "Chad"), | |
TH("TH", "Thailand"), | |
TJ("TJ", "Tajikistan"), | |
TK("TK", "Tokelau"), | |
TL("TL", "East Timor"), | |
TM("TM", "Turkmenistan"), | |
TN("TN", "Tunisia"), | |
TO("TO", "Tonga"), | |
TR("TR", "Turkey"), | |
TW("TW", "Taiwan"), | |
UA("UA", "Ukraine"), | |
US("US", "United States"), | |
UY("UY", "Uruguay"), | |
UZ("UZ", "Uzbekistan"), | |
VE("VE", "Venezuela"), | |
VN("VN", "Vietnam"), | |
VU("VU", "Vanuatu"), | |
WS("WS", "Samoa (western)"), | |
ZA("ZA", "South Africa"); | |
companion object { | |
private var codeMap:Map<String, CountryCode>? = null | |
private var countryMap:Map<String, CountryCode>? = null | |
fun fromCode(code: String): CountryCode? | |
= (codeMap ?: entries.associateBy{it.code}.also{codeMap = it})[code] | |
fun fromCountry(fullName: String): CountryCode? | |
= (countryMap ?: entries.associateBy{ it.fullName.lowercase() }.also{countryMap = it})[fullName.lowercase()] | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
class DstRule( | |
val fromYear: Int, val toYear: Int, | |
val startMonth: Int, val startDayRule: String, val startTimeSeconds: Int, | |
val endMonth: Int, val endDayRule: String, val endTimeSeconds: Int, | |
val saveSeconds: Int | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
expect fun getCurrentZoneInfo():Zone? | |
expect fun epochMsNow():Long |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
class Period( | |
val stdOffsetSeconds: Int, // 표준 오프셋 (초) | |
val dstSaveSeconds: Int, // 서머타임 시 추가되는 시간 (초). 없으면 0. | |
val format: String, // 시간대 약어 (예: "EST", "E%sT") | |
val untilEpochSeconds: Long // 이 기간이 유효한 마지막 시점 (UTC 에포크 초) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
class TimeFormat(val format:List<Item>) { | |
fun interface Item {operator fun invoke(zoneTime:ZoneTime):String} | |
class Str(val value: String):Item {override fun invoke(zoneTime:ZoneTime):String = value} | |
companion object{ | |
val Year4:Item = Item{it.year.toString().padStart(4, '0')} | |
val Year2:Item = Item{(it.year % 100).toString().padStart(2, '0')} | |
val Month2:Item = Item{it.month.toString().padStart(2, '0')} | |
val Month1:Item = Item{it.month.toString()} | |
val Day2:Item = Item{it.day.toString().padStart(2, '0')} | |
val Day1:Item = Item{it.day.toString()} | |
val Hour24_2:Item = Item{it.hour.toString().padStart(2, '0')} | |
val Hour24_1:Item = Item{it.hour.toString()} | |
val Hour12_2:Item = Item{ | |
val h = if (it.hour == 0 || it.hour == 12) 12 else it.hour % 12 | |
h.toString().padStart(2, '0') | |
} | |
val Hour12_1:Item = Item{ | |
val h = if (it.hour == 0 || it.hour == 12) 12 else it.hour % 12 | |
h.toString() | |
} | |
val Minute2:Item = Item{it.minute.toString().padStart(2, '0')} | |
val Minute1:Item = Item{it.minute.toString()} | |
val Second2:Item = Item{it.second.toString().padStart(2, '0')} | |
val Second1:Item = Item{it.second.toString()} | |
val Millisecond3:Item = Item{it.ms.toString().padStart(3, '0')} | |
val AmPmUpper:Item = Item{if(it.hour < 12) "AM" else "PM"} | |
val AmPmLower:Item = Item{if(it.hour < 12) "am" else "pm"} | |
private val TOKEN_MAP = mapOf( | |
"YYYY" to Year4, "YY" to Year2, | |
"MM" to Month2, "M" to Month1, | |
"DD" to Day2, "D" to Day1, | |
"HH" to Hour24_2, "H" to Hour24_1, "hh" to Hour12_2, "h" to Hour12_1, | |
"mm" to Minute2, "m" to Minute1, "ss" to Second2, "s" to Second1, | |
"SSS" to Millisecond3, | |
"A" to AmPmUpper, "a" to AmPmLower | |
) | |
private val SORTED_TOKENS = TOKEN_MAP.keys.sortedByDescending { it.length } | |
private val cache = mutableMapOf<String, TimeFormat>() | |
operator fun invoke(format:String):TimeFormat = cache.getOrPut(format) { | |
val items = mutableListOf<Item>() | |
var i = 0 | |
val literalBuffer = StringBuilder() | |
while (i < format.length) { | |
val matchedToken = SORTED_TOKENS.find { format.startsWith(it, i) } | |
if (matchedToken != null) { | |
if (literalBuffer.isNotEmpty()) { | |
items.add(Str(literalBuffer.toString())) | |
literalBuffer.clear() | |
} | |
items.add(TOKEN_MAP.getValue(matchedToken)) | |
i += matchedToken.length | |
} else { | |
literalBuffer.append(format[i]) | |
i++ | |
} | |
} | |
if (literalBuffer.isNotEmpty()) items.add(Str(literalBuffer.toString())) | |
TimeFormat(items) | |
} | |
operator fun invoke(vararg items:Item):TimeFormat = TimeFormat(items.toList()) | |
} | |
fun toString(zoneTime:ZoneTime):String = format.joinToString(""){it(zoneTime)} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
object TimeUtil { | |
internal fun isLeapYear(year:Int):Boolean = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) | |
internal fun daysInYear(year:Int):Int = if(isLeapYear(year)) 366 else 365 | |
internal fun daysInMonth(year:Int, month:Int): Int = when(month){ | |
2 -> if (isLeapYear(year)) 29 else 28 | |
4, 6, 9, 11 -> 30 | |
else -> 31 | |
} | |
internal fun floorDiv(x: Long, y: Long): Long { | |
var r = x / y | |
if ((x xor y) < 0 && r * y != x) r -= 1 | |
return r | |
} | |
internal fun floorMod(x: Long, y: Long): Long { | |
val r = x - floorDiv(x, y) * y | |
return r | |
} | |
@PublishedApi internal fun epochDayFromCivil(y0: Int, m: Int, d0: Int): Long { | |
var y = y0 | |
val d = d0 | |
y -= if (m <= 2) 1 else 0 | |
val era = if (y >= 0) y / 400 else (y - 399) / 400 | |
val yoe = y - era * 400 // [0,399] | |
val mp = m + if (m > 2) -3 else 9 // Mar=0..Feb=11 | |
val doy = (153 * mp + 2) / 5 + d - 1 // [0,365] | |
val doe = yoe * 365 + yoe / 4 - yoe / 100 + doy | |
return era * 146_097L + doe - 719_468L | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@file:Suppress("NOTHING_TO_INLINE") | |
package kore.time | |
import kotlin.math.abs | |
class UtcTime @PublishedApi internal constructor(val epochMs:Long, val offsetMs:Int){ | |
companion object{ | |
@PublishedApi internal val RFC3339_REGEX = """^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$""".toRegex() | |
inline operator fun invoke(epochMs:Long, offsetMs:Int = 0):UtcTime = UtcTime(epochMs, offsetMs) | |
inline operator fun invoke(zoneTime: ZoneTime):UtcTime = zoneTime.toUtcTime() | |
inline operator fun invoke(saved:String):UtcTime?{ | |
val s = saved.trim() | |
return if (s.startsWith("zt0:")) { //zt0:info.area:epochMs:offsetMs | |
val (_, _, epoch, offset) = s.split(":") | |
UtcTime(epoch.toLong(), offset.toInt()) | |
}else{ | |
val m = RFC3339_REGEX.matchEntire(s) ?: return null | |
val (ys, ms, ds, hs, mins, ss, fracs, off) = m.destructured | |
val year = ys.toInt() | |
val month = ms.toInt() | |
val day = ds.toInt() | |
val hour = hs.toInt() | |
val minute = mins.toInt() | |
val second = ss.toInt() | |
val offsetMs = when (off) { | |
"Z" -> 0 | |
else -> { | |
val sign = if (off[0] == '-') -1 else 1 | |
val oh = off.substring(1, 3).toInt() | |
val om = off.substring(4, 6).toInt() | |
sign * (oh * 3_600_000 + om * 60_000) | |
} | |
} | |
val milli = if (fracs.isEmpty()) 0 else (fracs.padEnd(3, '0').take(3).toInt()) | |
val epochDay = TimeUtil.epochDayFromCivil(year, month, day) | |
val wallMs = epochDay * 86_400_000L + | |
hour * 3_600_000L + | |
minute * 60_000L + | |
second * 1_000L + | |
milli | |
val utcMs = wallMs - offsetMs | |
UtcTime(utcMs, offsetMs) | |
} | |
} | |
} | |
val localEpochMs:Long = epochMs + offsetMs | |
private var isoString:String? = null | |
fun add(day:Int = 0, hour:Int = 0, minute:Int = 0, second:Int = 0, ms:Int = 0):UtcTime | |
= UtcTime( | |
epochMs + day.toLong() * 86_400_000L + hour.toLong() * 3_600_000L + minute.toLong() * 60_000L + second.toLong() * 1_000L + ms.toLong(), | |
offsetMs | |
) | |
inline fun diffMS(other:UtcTime):Long = epochMs - other.epochMs | |
inline fun diffSecond(other:UtcTime):Long = diffMS(other) / 1000 | |
inline fun diffMinute(other:UtcTime):Long = diffMS(other) / 60000 | |
inline fun diffHour(other:UtcTime):Long = diffMS(other) / 3600000 | |
inline fun diffDay(other:UtcTime):Long = diffMS(other) / 86400000 | |
inline fun year(zone: Zone): Int = toZoneTime(zone).year | |
inline fun month(zone: Zone): Int = toZoneTime(zone).month | |
inline fun day(zone: Zone): Int = toZoneTime(zone).day | |
inline fun hour(zone: Zone): Int = toZoneTime(zone).hour | |
inline fun minute(zone: Zone): Int = toZoneTime(zone).minute | |
inline fun second(zone: Zone): Int = toZoneTime(zone).second | |
inline fun ms(): Int = (((epochMs % 1000L) + 1000L) % 1000L).toInt() | |
fun toZoneTime(zone: Zone): ZoneTime { | |
val idx = zone.periodIndexByUtc(epochMs) | |
val offsetMs = zone.totalOffsetMs[idx] | |
val localEpochMs = epochMs + offsetMs | |
val millisPerDay = 86_400_000L | |
val epochDay = TimeUtil.floorDiv(localEpochMs, millisPerDay) | |
val millisOfDay = TimeUtil.floorMod(localEpochMs, millisPerDay).toInt() | |
var year = 1970 | |
var days = epochDay | |
while (days < 0 || days >= TimeUtil.daysInYear(year)) { | |
if (days < 0) { year--; days += TimeUtil.daysInYear(year) } | |
else { days -= TimeUtil.daysInYear(year); year++ } | |
} | |
var month = 1 | |
while (days >= TimeUtil.daysInMonth(year, month)) { | |
days -= TimeUtil.daysInMonth(year, month) | |
month++ | |
} | |
val day = (days + 1).toInt() | |
val hour = millisOfDay / 3_600_000 | |
val minute = (millisOfDay % 3_600_000) / 60_000 | |
val second = (millisOfDay % 60_000) / 1_000 | |
val ms = millisOfDay % 1_000 | |
return ZoneTime(year, month, day, hour, minute, second, ms, zone) | |
} | |
override fun equals(other: Any?): Boolean = other is UtcTime && epochMs == other.epochMs | |
override fun hashCode(): Int = epochMs.hashCode() | |
private inline fun pad2(n: Int) = n.toString().padStart(2, '0') | |
private inline fun pad3(n: Int) = n.toString().padStart(3, '0') | |
private inline fun pad4(n: Int) = n.toString().padStart(4, '0') | |
fun toISO8601(isRFC3339:Boolean = true):String{ | |
val s = isoString ?: toZoneTime(Zone.ephemeral(offsetMs)).let{zt-> | |
StringBuilder(32) | |
.append(pad4(zt.year)).append('-') | |
.append(pad2(zt.month)).append('-') | |
.append(pad2(zt.day)).append('T') | |
.append(pad2(zt.hour)).append(':') | |
.append(pad2(zt.minute)).append(':') | |
.append(pad2(zt.second)).also{ | |
if(!isRFC3339 || zt.ms != 0) it.append('.').append(pad3(zt.ms)) | |
if (offsetMs == 0) it.append('Z') | |
else { | |
val absMs = abs(offsetMs) | |
it.append(if (offsetMs < 0) '-' else '+') | |
.append(pad2(absMs / 3_600_000)).append(':') | |
.append(pad2((absMs % 3_600_000) / 60_000)) | |
} | |
}.toString().also{isoString = it} | |
} | |
return if (!isRFC3339 && s.endsWith("Z")) s.dropLast(1) + "+00:00" else s | |
} | |
override fun toString():String = toISO8601() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@file:Suppress("NOTHING_TO_INLINE") | |
package kore.time | |
import kotlin.math.* | |
class Zone(val area:String, val countryCode:CountryCode, val lat:Double, val lon:Double, val utcOffset:Int, private val p:List<Period>){ | |
companion object{ | |
private const val EOT_SEC: Long = 253_402_300_799L | |
private const val EPHEMERAL = "EPHEMERAL" | |
internal val UTC = Zone(EPHEMERAL, CountryCode.KR, 0.0, 0.0, 0, listOf(Period(0, 0, "UTC", EOT_SEC))) | |
operator fun get(area:String):Zone? = zones[area.lowercase()] | |
internal fun ephemeral(offsetMs: Int): Zone = Zone( | |
EPHEMERAL, CountryCode.KR, 0.0, 0.0, offsetMs / 1000, | |
listOf(Period(offsetMs / 1000, 0, "UNK", EOT_SEC)) // 초 단위 | |
) | |
private inline fun Double.rad(): Double = this * PI / 180.0 | |
fun findClose(lat:Double, lon:Double): Zone?{ | |
val candidates = zones.values | |
if (candidates.isEmpty()) return null | |
val latRad = lat.rad() | |
val cosLat = cos(latRad) | |
var best: Zone? = null | |
var bestD2 = Double.POSITIVE_INFINITY | |
for (z in candidates) { | |
val dLat = (z.lat - lat).rad() | |
var dLon = (z.lon - lon).rad() | |
// 날짜변경선 래핑: [-π, π]로 접기 | |
if (dLon > PI) dLon -= 2 * PI | |
if (dLon < -PI) dLon += 2 * PI | |
// equirectangular 근사: x=Δλ·cos φ, y=Δφ | |
val x = dLon * cosLat | |
val d2 = x * x + dLat * dLat | |
if (d2 < bestD2) { | |
bestD2 = d2 | |
best = z | |
} | |
} | |
return best | |
} | |
} | |
private var _periods:List<Period>? = null | |
val periods get() = _periods ?: ( | |
if(p.isEmpty()) listOf(Period(utcOffset, 0, "FIX", EOT_SEC)) | |
else p.sortedBy{it.untilEpochSeconds} | |
).also{_periods = it} | |
private var _totalOffsetMs:IntArray? = null | |
internal val totalOffsetMs:IntArray get() = _totalOffsetMs?: IntArray(periods.size) { i -> | |
(periods[i].stdOffsetSeconds + periods[i].dstSaveSeconds) * 1000 | |
}.also{_totalOffsetMs = it} | |
private var _endExclMs:LongArray? = null | |
internal val endExclMs:LongArray get() = _endExclMs ?: LongArray(periods.size){i -> | |
val s = periods[i].untilEpochSeconds | |
val ms = s * 1000L | |
if (ms > Long.MAX_VALUE - 1000L) Long.MAX_VALUE else ms + 1000L | |
}.also{_endExclMs = it} | |
fun periodIndexByUtc(epochMs: Long): Int {/** epochMs가 속한 period 인덱스 (UTC 기준, 이진 탐색) */ | |
var lo = 0 | |
var hi = endExclMs.size | |
while (lo < hi) { | |
val mid = (lo + hi) ushr 1 | |
if (epochMs < endExclMs[mid]) hi = mid else lo = mid + 1 | |
} | |
return (lo - 1).coerceIn(0, periods.lastIndex) | |
} | |
init{ | |
if(area != EPHEMERAL) { | |
if(area !in zones) zones[area] = this else throw Throwable("Zone already exists: $area") | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
@PublishedApi internal val zones:HashMap<String, Zone> = hashMapOf( | |
"africa/abidjan" to AFRICA_ABIDJAN, | |
"africa/accra" to AFRICA_ACCRA, | |
"africa/addis_ababa" to AFRICA_ADDIS_ABABA, | |
"africa/algiers" to AFRICA_ALGIERS, | |
"africa/asmara" to AFRICA_ASMARA, | |
"africa/asmera" to AFRICA_ASMERA, | |
"africa/bamako" to AFRICA_BAMAKO, | |
"africa/bangui" to AFRICA_BANGUI, | |
"africa/banjul" to AFRICA_BANJUL, | |
"africa/bissau" to AFRICA_BISSAU, | |
"africa/blantyre" to AFRICA_BLANTYRE, | |
"africa/brazzaville" to AFRICA_BRAZZAVILLE, | |
"africa/bujumbura" to AFRICA_BUJUMBURA, | |
"africa/cairo" to AFRICA_CAIRO, | |
"africa/casablanca" to AFRICA_CASABLANCA, | |
"africa/ceuta" to AFRICA_CEUTA, | |
"africa/conakry" to AFRICA_CONAKRY, | |
"africa/dakar" to AFRICA_DAKAR, | |
"africa/dar_es_salaam" to AFRICA_DAR_ES_SALAAM, | |
"africa/djibouti" to AFRICA_DJIBOUTI, | |
"africa/douala" to AFRICA_DOUALA, | |
"africa/el_aaiun" to AFRICA_EL_AAIUN, | |
"africa/freetown" to AFRICA_FREETOWN, | |
"africa/gaborone" to AFRICA_GABORONE, | |
"africa/harare" to AFRICA_HARARE, | |
"africa/johannesburg" to AFRICA_JOHANNESBURG, | |
"africa/juba" to AFRICA_JUBA, | |
"africa/kampala" to AFRICA_KAMPALA, | |
"africa/khartoum" to AFRICA_KHARTOUM, | |
"africa/kigali" to AFRICA_KIGALI, | |
"africa/kinshasa" to AFRICA_KINSHASA, | |
"africa/lagos" to AFRICA_LAGOS, | |
"africa/libreville" to AFRICA_LIBREVILLE, | |
"africa/lome" to AFRICA_LOME, | |
"africa/luanda" to AFRICA_LUANDA, | |
"africa/lubumbashi" to AFRICA_LUBUMBASHI, | |
"africa/lusaka" to AFRICA_LUSAKA, | |
"africa/malabo" to AFRICA_MALABO, | |
"africa/maputo" to AFRICA_MAPUTO, | |
"africa/maseru" to AFRICA_MASERU, | |
"africa/mbabane" to AFRICA_MBABANE, | |
"africa/mogadishu" to AFRICA_MOGADISHU, | |
"africa/monrovia" to AFRICA_MONROVIA, | |
"africa/nairobi" to AFRICA_NAIROBI, | |
"africa/ndjamena" to AFRICA_NDJAMENA, | |
"africa/niamey" to AFRICA_NIAMEY, | |
"africa/nouakchott" to AFRICA_NOUAKCHOTT, | |
"africa/ouagadougou" to AFRICA_OUAGADOUGOU, | |
"africa/porto-novo" to AFRICA_PORTO_NOVO, | |
"africa/sao_tome" to AFRICA_SAO_TOME, | |
"africa/timbuktu" to AFRICA_TIMBUKTU, | |
"africa/tripoli" to AFRICA_TRIPOLI, | |
"africa/tunis" to AFRICA_TUNIS, | |
"africa/windhoek" to AFRICA_WINDHOEK, | |
"america/adak" to AMERICA_ADAK, | |
"america/anchorage" to AMERICA_ANCHORAGE, | |
"america/anguilla" to AMERICA_ANGUILLA, | |
"america/antigua" to AMERICA_ANTIGUA, | |
"america/araguaina" to AMERICA_ARAGUAINA, | |
"america/argentina/buenos_aires" to AMERICA_ARGENTINA_BUENOS_AIRES, | |
"america/argentina/catamarca" to AMERICA_ARGENTINA_CATAMARCA, | |
"america/argentina/comodrivadavia" to AMERICA_ARGENTINA_COMODRIVADAVIA, | |
"america/argentina/cordoba" to AMERICA_ARGENTINA_CORDOBA, | |
"america/argentina/jujuy" to AMERICA_ARGENTINA_JUJUY, | |
"america/argentina/la_rioja" to AMERICA_ARGENTINA_LA_RIOJA, | |
"america/argentina/mendoza" to AMERICA_ARGENTINA_MENDOZA, | |
"america/argentina/rio_gallegos" to AMERICA_ARGENTINA_RIO_GALLEGOS, | |
"america/argentina/salta" to AMERICA_ARGENTINA_SALTA, | |
"america/argentina/san_juan" to AMERICA_ARGENTINA_SAN_JUAN, | |
"america/argentina/san_luis" to AMERICA_ARGENTINA_SAN_LUIS, | |
"america/argentina/tucuman" to AMERICA_ARGENTINA_TUCUMAN, | |
"america/argentina/ushuaia" to AMERICA_ARGENTINA_USHUAIA, | |
"america/aruba" to AMERICA_ARUBA, | |
"america/asuncion" to AMERICA_ASUNCION, | |
"america/atikokan" to AMERICA_ATIKOKAN, | |
"america/atka" to AMERICA_ATKA, | |
"america/bahia" to AMERICA_BAHIA, | |
"america/bahia_banderas" to AMERICA_BAHIA_BANDERAS, | |
"america/barbados" to AMERICA_BARBADOS, | |
"america/belem" to AMERICA_BELEM, | |
"america/belize" to AMERICA_BELIZE, | |
"america/blanc-sablon" to AMERICA_BLANC_SABLON, | |
"america/boa_vista" to AMERICA_BOA_VISTA, | |
"america/bogota" to AMERICA_BOGOTA, | |
"america/boise" to AMERICA_BOISE, | |
"america/buenos_aires" to AMERICA_BUENOS_AIRES, | |
"america/cambridge_bay" to AMERICA_CAMBRIDGE_BAY, | |
"america/campo_grande" to AMERICA_CAMPO_GRANDE, | |
"america/cancun" to AMERICA_CANCUN, | |
"america/caracas" to AMERICA_CARACAS, | |
"america/catamarca" to AMERICA_CATAMARCA, | |
"america/cayenne" to AMERICA_CAYENNE, | |
"america/cayman" to AMERICA_CAYMAN, | |
"america/chicago" to AMERICA_CHICAGO, | |
"america/chihuahua" to AMERICA_CHIHUAHUA, | |
"america/ciudad_juarez" to AMERICA_CIUDAD_JUAREZ, | |
"america/coral_harbour" to AMERICA_CORAL_HARBOUR, | |
"america/cordoba" to AMERICA_CORDOBA, | |
"america/costa_rica" to AMERICA_COSTA_RICA, | |
"america/creston" to AMERICA_CRESTON, | |
"america/cuiaba" to AMERICA_CUIABA, | |
"america/curacao" to AMERICA_CURACAO, | |
"america/danmarkshavn" to AMERICA_DANMARKSHAVN, | |
"america/dawson" to AMERICA_DAWSON, | |
"america/dawson_creek" to AMERICA_DAWSON_CREEK, | |
"america/denver" to AMERICA_DENVER, | |
"america/detroit" to AMERICA_DETROIT, | |
"america/dominica" to AMERICA_DOMINICA, | |
"america/edmonton" to AMERICA_EDMONTON, | |
"america/eirunepe" to AMERICA_EIRUNEPE, | |
"america/el_salvador" to AMERICA_EL_SALVADOR, | |
"america/ensenada" to AMERICA_ENSENADA, | |
"america/fort_nelson" to AMERICA_FORT_NELSON, | |
"america/fort_wayne" to AMERICA_FORT_WAYNE, | |
"america/fortaleza" to AMERICA_FORTALEZA, | |
"america/glace_bay" to AMERICA_GLACE_BAY, | |
"america/godthab" to AMERICA_GODTHAB, | |
"america/goose_bay" to AMERICA_GOOSE_BAY, | |
"america/grand_turk" to AMERICA_GRAND_TURK, | |
"america/grenada" to AMERICA_GRENADA, | |
"america/guadeloupe" to AMERICA_GUADELOUPE, | |
"america/guatemala" to AMERICA_GUATEMALA, | |
"america/guayaquil" to AMERICA_GUAYAQUIL, | |
"america/guyana" to AMERICA_GUYANA, | |
"america/halifax" to AMERICA_HALIFAX, | |
"america/havana" to AMERICA_HAVANA, | |
"america/hermosillo" to AMERICA_HERMOSILLO, | |
"america/indiana/indianapolis" to AMERICA_INDIANA_INDIANAPOLIS, | |
"america/indiana/knox" to AMERICA_INDIANA_KNOX, | |
"america/indiana/marengo" to AMERICA_INDIANA_MARENGO, | |
"america/indiana/petersburg" to AMERICA_INDIANA_PETERSBURG, | |
"america/indiana/tell_city" to AMERICA_INDIANA_TELL_CITY, | |
"america/indiana/vevay" to AMERICA_INDIANA_VEVAY, | |
"america/indiana/vincennes" to AMERICA_INDIANA_VINCENNES, | |
"america/indiana/winamac" to AMERICA_INDIANA_WINAMAC, | |
"america/indianapolis" to AMERICA_INDIANAPOLIS, | |
"america/inuvik" to AMERICA_INUVIK, | |
"america/iqaluit" to AMERICA_IQALUIT, | |
"america/jamaica" to AMERICA_JAMAICA, | |
"america/jujuy" to AMERICA_JUJUY, | |
"america/juneau" to AMERICA_JUNEAU, | |
"america/kentucky/louisville" to AMERICA_KENTUCKY_LOUISVILLE, | |
"america/kentucky/monticello" to AMERICA_KENTUCKY_MONTICELLO, | |
"america/knox_in" to AMERICA_KNOX_IN, | |
"america/kralendijk" to AMERICA_KRALENDIJK, | |
"america/la_paz" to AMERICA_LA_PAZ, | |
"america/lima" to AMERICA_LIMA, | |
"america/los_angeles" to AMERICA_LOS_ANGELES, | |
"america/louisville" to AMERICA_LOUISVILLE, | |
"america/lower_princes" to AMERICA_LOWER_PRINCES, | |
"america/maceio" to AMERICA_MACEIO, | |
"america/managua" to AMERICA_MANAGUA, | |
"america/manaus" to AMERICA_MANAUS, | |
"america/marigot" to AMERICA_MARIGOT, | |
"america/martinique" to AMERICA_MARTINIQUE, | |
"america/matamoros" to AMERICA_MATAMOROS, | |
"america/mazatlan" to AMERICA_MAZATLAN, | |
"america/mendoza" to AMERICA_MENDOZA, | |
"america/menominee" to AMERICA_MENOMINEE, | |
"america/merida" to AMERICA_MERIDA, | |
"america/metlakatla" to AMERICA_METLAKATLA, | |
"america/mexico_city" to AMERICA_MEXICO_CITY, | |
"america/miquelon" to AMERICA_MIQUELON, | |
"america/moncton" to AMERICA_MONCTON, | |
"america/monterrey" to AMERICA_MONTERREY, | |
"america/montevideo" to AMERICA_MONTEVIDEO, | |
"america/montreal" to AMERICA_MONTREAL, | |
"america/montserrat" to AMERICA_MONTSERRAT, | |
"america/nassau" to AMERICA_NASSAU, | |
"america/new_york" to AMERICA_NEW_YORK, | |
"america/nipigon" to AMERICA_NIPIGON, | |
"america/nome" to AMERICA_NOME, | |
"america/noronha" to AMERICA_NORONHA, | |
"america/north_dakota/beulah" to AMERICA_NORTH_DAKOTA_BEULAH, | |
"america/north_dakota/center" to AMERICA_NORTH_DAKOTA_CENTER, | |
"america/north_dakota/new_salem" to AMERICA_NORTH_DAKOTA_NEW_SALEM, | |
"america/nuuk" to AMERICA_NUUK, | |
"america/ojinaga" to AMERICA_OJINAGA, | |
"america/panama" to AMERICA_PANAMA, | |
"america/pangnirtung" to AMERICA_PANGNIRTUNG, | |
"america/paramaribo" to AMERICA_PARAMARIBO, | |
"america/phoenix" to AMERICA_PHOENIX, | |
"america/port-au-prince" to AMERICA_PORT_AU_PRINCE, | |
"america/port_of_spain" to AMERICA_PORT_OF_SPAIN, | |
"america/porto_acre" to AMERICA_PORTO_ACRE, | |
"america/porto_velho" to AMERICA_PORTO_VELHO, | |
"america/puerto_rico" to AMERICA_PUERTO_RICO, | |
"america/punta_arenas" to AMERICA_PUNTA_ARENAS, | |
"america/rainy_river" to AMERICA_RAINY_RIVER, | |
"america/rankin_inlet" to AMERICA_RANKIN_INLET, | |
"america/recife" to AMERICA_RECIFE, | |
"america/regina" to AMERICA_REGINA, | |
"america/resolute" to AMERICA_RESOLUTE, | |
"america/rio_branco" to AMERICA_RIO_BRANCO, | |
"america/rosario" to AMERICA_ROSARIO, | |
"america/santa_isabel" to AMERICA_SANTA_ISABEL, | |
"america/santarem" to AMERICA_SANTAREM, | |
"america/santiago" to AMERICA_SANTIAGO, | |
"america/santo_domingo" to AMERICA_SANTO_DOMINGO, | |
"america/sao_paulo" to AMERICA_SAO_PAULO, | |
"america/scoresbysund" to AMERICA_SCORESBYSUND, | |
"america/shiprock" to AMERICA_SHIPROCK, | |
"america/sitka" to AMERICA_SITKA, | |
"america/st_barthelemy" to AMERICA_ST_BARTHELEMY, | |
"america/st_johns" to AMERICA_ST_JOHNS, | |
"america/st_kitts" to AMERICA_ST_KITTS, | |
"america/st_lucia" to AMERICA_ST_LUCIA, | |
"america/st_thomas" to AMERICA_ST_THOMAS, | |
"america/st_vincent" to AMERICA_ST_VINCENT, | |
"america/swift_current" to AMERICA_SWIFT_CURRENT, | |
"america/tegucigalpa" to AMERICA_TEGUCIGALPA, | |
"america/thule" to AMERICA_THULE, | |
"america/thunder_bay" to AMERICA_THUNDER_BAY, | |
"america/tijuana" to AMERICA_TIJUANA, | |
"america/toronto" to AMERICA_TORONTO, | |
"america/tortola" to AMERICA_TORTOLA, | |
"america/vancouver" to AMERICA_VANCOUVER, | |
"america/virgin" to AMERICA_VIRGIN, | |
"america/whitehorse" to AMERICA_WHITEHORSE, | |
"america/winnipeg" to AMERICA_WINNIPEG, | |
"america/yakutat" to AMERICA_YAKUTAT, | |
"america/yellowknife" to AMERICA_YELLOWKNIFE, | |
"antarctica/casey" to ANTARCTICA_CASEY, | |
"antarctica/davis" to ANTARCTICA_DAVIS, | |
"antarctica/dumontdurville" to ANTARCTICA_DUMONTDURVILLE, | |
"antarctica/macquarie" to ANTARCTICA_MACQUARIE, | |
"antarctica/mawson" to ANTARCTICA_MAWSON, | |
"antarctica/mcmurdo" to ANTARCTICA_MCMURDO, | |
"antarctica/palmer" to ANTARCTICA_PALMER, | |
"antarctica/rothera" to ANTARCTICA_ROTHERA, | |
"antarctica/south_pole" to ANTARCTICA_SOUTH_POLE, | |
"antarctica/syowa" to ANTARCTICA_SYOWA, | |
"antarctica/troll" to ANTARCTICA_TROLL, | |
"antarctica/vostok" to ANTARCTICA_VOSTOK, | |
"arctic/longyearbyen" to ARCTIC_LONGYEARBYEN, | |
"asia/aden" to ASIA_ADEN, | |
"asia/almaty" to ASIA_ALMATY, | |
"asia/amman" to ASIA_AMMAN, | |
"asia/anadyr" to ASIA_ANADYR, | |
"asia/aqtau" to ASIA_AQTAU, | |
"asia/aqtobe" to ASIA_AQTOBE, | |
"asia/ashgabat" to ASIA_ASHGABAT, | |
"asia/ashkhabad" to ASIA_ASHKHABAD, | |
"asia/atyrau" to ASIA_ATYRAU, | |
"asia/baghdad" to ASIA_BAGHDAD, | |
"asia/bahrain" to ASIA_BAHRAIN, | |
"asia/baku" to ASIA_BAKU, | |
"asia/bangkok" to ASIA_BANGKOK, | |
"asia/barnaul" to ASIA_BARNAUL, | |
"asia/beirut" to ASIA_BEIRUT, | |
"asia/bishkek" to ASIA_BISHKEK, | |
"asia/brunei" to ASIA_BRUNEI, | |
"asia/calcutta" to ASIA_CALCUTTA, | |
"asia/chita" to ASIA_CHITA, | |
"asia/choibalsan" to ASIA_CHOIBALSAN, | |
"asia/chongqing" to ASIA_CHONGQING, | |
"asia/chungking" to ASIA_CHUNGKING, | |
"asia/colombo" to ASIA_COLOMBO, | |
"asia/dacca" to ASIA_DACCA, | |
"asia/damascus" to ASIA_DAMASCUS, | |
"asia/dhaka" to ASIA_DHAKA, | |
"asia/dili" to ASIA_DILI, | |
"asia/dubai" to ASIA_DUBAI, | |
"asia/dushanbe" to ASIA_DUSHANBE, | |
"asia/famagusta" to ASIA_FAMAGUSTA, | |
"asia/gaza" to ASIA_GAZA, | |
"asia/harbin" to ASIA_HARBIN, | |
"asia/hebron" to ASIA_HEBRON, | |
"asia/ho_chi_minh" to ASIA_HO_CHI_MINH, | |
"asia/hong_kong" to ASIA_HONG_KONG, | |
"asia/hovd" to ASIA_HOVD, | |
"asia/irkutsk" to ASIA_IRKUTSK, | |
"asia/istanbul" to ASIA_ISTANBUL, | |
"asia/jakarta" to ASIA_JAKARTA, | |
"asia/jayapura" to ASIA_JAYAPURA, | |
"asia/jerusalem" to ASIA_JERUSALEM, | |
"asia/kabul" to ASIA_KABUL, | |
"asia/kamchatka" to ASIA_KAMCHATKA, | |
"asia/karachi" to ASIA_KARACHI, | |
"asia/kashgar" to ASIA_KASHGAR, | |
"asia/kathmandu" to ASIA_KATHMANDU, | |
"asia/katmandu" to ASIA_KATMANDU, | |
"asia/khandyga" to ASIA_KHANDYGA, | |
"asia/kolkata" to ASIA_KOLKATA, | |
"asia/krasnoyarsk" to ASIA_KRASNOYARSK, | |
"asia/kuala_lumpur" to ASIA_KUALA_LUMPUR, | |
"asia/kuching" to ASIA_KUCHING, | |
"asia/kuwait" to ASIA_KUWAIT, | |
"asia/macao" to ASIA_MACAO, | |
"asia/macau" to ASIA_MACAU, | |
"asia/magadan" to ASIA_MAGADAN, | |
"asia/makassar" to ASIA_MAKASSAR, | |
"asia/manila" to ASIA_MANILA, | |
"asia/muscat" to ASIA_MUSCAT, | |
"asia/nicosia" to ASIA_NICOSIA, | |
"asia/novokuznetsk" to ASIA_NOVOKUZNETSK, | |
"asia/novosibirsk" to ASIA_NOVOSIBIRSK, | |
"asia/omsk" to ASIA_OMSK, | |
"asia/oral" to ASIA_ORAL, | |
"asia/phnom_penh" to ASIA_PHNOM_PENH, | |
"asia/pontianak" to ASIA_PONTIANAK, | |
"asia/pyongyang" to ASIA_PYONGYANG, | |
"asia/qatar" to ASIA_QATAR, | |
"asia/qostanay" to ASIA_QOSTANAY, | |
"asia/qyzylorda" to ASIA_QYZYLORDA, | |
"asia/rangoon" to ASIA_RANGOON, | |
"asia/riyadh" to ASIA_RIYADH, | |
"asia/saigon" to ASIA_SAIGON, | |
"asia/sakhalin" to ASIA_SAKHALIN, | |
"asia/samarkand" to ASIA_SAMARKAND, | |
"asia/seoul" to ASIA_SEOUL, | |
"asia/shanghai" to ASIA_SHANGHAI, | |
"asia/singapore" to ASIA_SINGAPORE, | |
"asia/srednekolymsk" to ASIA_SREDNEKOLYMSK, | |
"asia/taipei" to ASIA_TAIPEI, | |
"asia/tashkent" to ASIA_TASHKENT, | |
"asia/tbilisi" to ASIA_TBILISI, | |
"asia/tehran" to ASIA_TEHRAN, | |
"asia/tel_aviv" to ASIA_TEL_AVIV, | |
"asia/thimbu" to ASIA_THIMBU, | |
"asia/thimphu" to ASIA_THIMPHU, | |
"asia/tokyo" to ASIA_TOKYO, | |
"asia/tomsk" to ASIA_TOMSK, | |
"asia/ujung_pandang" to ASIA_UJUNG_PANDANG, | |
"asia/ulaanbaatar" to ASIA_ULAANBAATAR, | |
"asia/ulan_bator" to ASIA_ULAN_BATOR, | |
"asia/urumqi" to ASIA_URUMQI, | |
"asia/ust-nera" to ASIA_UST_NERA, | |
"asia/vientiane" to ASIA_VIENTIANE, | |
"asia/vladivostok" to ASIA_VLADIVOSTOK, | |
"asia/yakutsk" to ASIA_YAKUTSK, | |
"asia/yangon" to ASIA_YANGON, | |
"asia/yekaterinburg" to ASIA_YEKATERINBURG, | |
"asia/yerevan" to ASIA_YEREVAN, | |
"atlantic/azores" to ATLANTIC_AZORES, | |
"atlantic/bermuda" to ATLANTIC_BERMUDA, | |
"atlantic/canary" to ATLANTIC_CANARY, | |
"atlantic/cape_verde" to ATLANTIC_CAPE_VERDE, | |
"atlantic/faeroe" to ATLANTIC_FAEROE, | |
"atlantic/faroe" to ATLANTIC_FAROE, | |
"atlantic/jan_mayen" to ATLANTIC_JAN_MAYEN, | |
"atlantic/madeira" to ATLANTIC_MADEIRA, | |
"atlantic/reykjavik" to ATLANTIC_REYKJAVIK, | |
"atlantic/south_georgia" to ATLANTIC_SOUTH_GEORGIA, | |
"atlantic/st_helena" to ATLANTIC_ST_HELENA, | |
"atlantic/stanley" to ATLANTIC_STANLEY, | |
"australia/act" to AUSTRALIA_ACT, | |
"australia/adelaide" to AUSTRALIA_ADELAIDE, | |
"australia/brisbane" to AUSTRALIA_BRISBANE, | |
"australia/broken_hill" to AUSTRALIA_BROKEN_HILL, | |
"australia/canberra" to AUSTRALIA_CANBERRA, | |
"australia/currie" to AUSTRALIA_CURRIE, | |
"australia/darwin" to AUSTRALIA_DARWIN, | |
"australia/eucla" to AUSTRALIA_EUCLA, | |
"australia/hobart" to AUSTRALIA_HOBART, | |
"australia/lhi" to AUSTRALIA_LHI, | |
"australia/lindeman" to AUSTRALIA_LINDEMAN, | |
"australia/lord_howe" to AUSTRALIA_LORD_HOWE, | |
"australia/melbourne" to AUSTRALIA_MELBOURNE, | |
"australia/nsw" to AUSTRALIA_NSW, | |
"australia/north" to AUSTRALIA_NORTH, | |
"australia/perth" to AUSTRALIA_PERTH, | |
"australia/queensland" to AUSTRALIA_QUEENSLAND, | |
"australia/south" to AUSTRALIA_SOUTH, | |
"australia/sydney" to AUSTRALIA_SYDNEY, | |
"australia/tasmania" to AUSTRALIA_TASMANIA, | |
"australia/victoria" to AUSTRALIA_VICTORIA, | |
"australia/west" to AUSTRALIA_WEST, | |
"australia/yancowinna" to AUSTRALIA_YANCOWINNA, | |
"brazil/acre" to BRAZIL_ACRE, | |
"brazil/denoronha" to BRAZIL_DENORONHA, | |
"brazil/east" to BRAZIL_EAST, | |
"brazil/west" to BRAZIL_WEST, | |
"cet" to CET, | |
"cst6cdt" to CST6CDT, | |
"canada/atlantic" to CANADA_ATLANTIC, | |
"canada/central" to CANADA_CENTRAL, | |
"canada/eastern" to CANADA_EASTERN, | |
"canada/mountain" to CANADA_MOUNTAIN, | |
"canada/newfoundland" to CANADA_NEWFOUNDLAND, | |
"canada/pacific" to CANADA_PACIFIC, | |
"canada/saskatchewan" to CANADA_SASKATCHEWAN, | |
"canada/yukon" to CANADA_YUKON, | |
"chile/continental" to CHILE_CONTINENTAL, | |
"chile/easterisland" to CHILE_EASTERISLAND, | |
"cuba" to CUBA, | |
"eet" to EET, | |
"est" to EST, | |
"est5edt" to EST5EDT, | |
"egypt" to EGYPT, | |
"eire" to EIRE, | |
"europe/amsterdam" to EUROPE_AMSTERDAM, | |
"europe/andorra" to EUROPE_ANDORRA, | |
"europe/astrakhan" to EUROPE_ASTRAKHAN, | |
"europe/athens" to EUROPE_ATHENS, | |
"europe/belfast" to EUROPE_BELFAST, | |
"europe/belgrade" to EUROPE_BELGRADE, | |
"europe/berlin" to EUROPE_BERLIN, | |
"europe/bratislava" to EUROPE_BRATISLAVA, | |
"europe/brussels" to EUROPE_BRUSSELS, | |
"europe/bucharest" to EUROPE_BUCHAREST, | |
"europe/budapest" to EUROPE_BUDAPEST, | |
"europe/busingen" to EUROPE_BUSINGEN, | |
"europe/chisinau" to EUROPE_CHISINAU, | |
"europe/copenhagen" to EUROPE_COPENHAGEN, | |
"europe/dublin" to EUROPE_DUBLIN, | |
"europe/gibraltar" to EUROPE_GIBRALTAR, | |
"europe/guernsey" to EUROPE_GUERNSEY, | |
"europe/helsinki" to EUROPE_HELSINKI, | |
"europe/isle_of_man" to EUROPE_ISLE_OF_MAN, | |
"europe/istanbul" to EUROPE_ISTANBUL, | |
"europe/jersey" to EUROPE_JERSEY, | |
"europe/kaliningrad" to EUROPE_KALININGRAD, | |
"europe/kiev" to EUROPE_KIEV, | |
"europe/kirov" to EUROPE_KIROV, | |
"europe/kyiv" to EUROPE_KYIV, | |
"europe/lisbon" to EUROPE_LISBON, | |
"europe/ljubljana" to EUROPE_LJUBLJANA, | |
"europe/london" to EUROPE_LONDON, | |
"europe/luxembourg" to EUROPE_LUXEMBOURG, | |
"europe/madrid" to EUROPE_MADRID, | |
"europe/malta" to EUROPE_MALTA, | |
"europe/mariehamn" to EUROPE_MARIEHAMN, | |
"europe/minsk" to EUROPE_MINSK, | |
"europe/monaco" to EUROPE_MONACO, | |
"europe/moscow" to EUROPE_MOSCOW, | |
"europe/nicosia" to EUROPE_NICOSIA, | |
"europe/oslo" to EUROPE_OSLO, | |
"europe/paris" to EUROPE_PARIS, | |
"europe/podgorica" to EUROPE_PODGORICA, | |
"europe/prague" to EUROPE_PRAGUE, | |
"europe/riga" to EUROPE_RIGA, | |
"europe/rome" to EUROPE_ROME, | |
"europe/samara" to EUROPE_SAMARA, | |
"europe/san_marino" to EUROPE_SAN_MARINO, | |
"europe/sarajevo" to EUROPE_SARAJEVO, | |
"europe/saratov" to EUROPE_SARATOV, | |
"europe/simferopol" to EUROPE_SIMFEROPOL, | |
"europe/skopje" to EUROPE_SKOPJE, | |
"europe/sofia" to EUROPE_SOFIA, | |
"europe/stockholm" to EUROPE_STOCKHOLM, | |
"europe/tallinn" to EUROPE_TALLINN, | |
"europe/tirane" to EUROPE_TIRANE, | |
"europe/tiraspol" to EUROPE_TIRASPOL, | |
"europe/ulyanovsk" to EUROPE_ULYANOVSK, | |
"europe/uzhgorod" to EUROPE_UZHGOROD, | |
"europe/vaduz" to EUROPE_VADUZ, | |
"europe/vatican" to EUROPE_VATICAN, | |
"europe/vienna" to EUROPE_VIENNA, | |
"europe/vilnius" to EUROPE_VILNIUS, | |
"europe/volgograd" to EUROPE_VOLGOGRAD, | |
"europe/warsaw" to EUROPE_WARSAW, | |
"europe/zagreb" to EUROPE_ZAGREB, | |
"europe/zaporozhye" to EUROPE_ZAPOROZHYE, | |
"europe/zurich" to EUROPE_ZURICH, | |
"gb" to GB, | |
"gb-eire" to GB_EIRE, | |
"hst" to HST, | |
"hongkong" to HONGKONG, | |
"iceland" to ICELAND, | |
"indian/antananarivo" to INDIAN_ANTANANARIVO, | |
"indian/chagos" to INDIAN_CHAGOS, | |
"indian/christmas" to INDIAN_CHRISTMAS, | |
"indian/cocos" to INDIAN_COCOS, | |
"indian/comoro" to INDIAN_COMORO, | |
"indian/kerguelen" to INDIAN_KERGUELEN, | |
"indian/mahe" to INDIAN_MAHE, | |
"indian/maldives" to INDIAN_MALDIVES, | |
"indian/mauritius" to INDIAN_MAURITIUS, | |
"indian/mayotte" to INDIAN_MAYOTTE, | |
"indian/reunion" to INDIAN_REUNION, | |
"iran" to IRAN, | |
"israel" to ISRAEL, | |
"jamaica" to JAMAICA, | |
"japan" to JAPAN, | |
"kwajalein" to KWAJALEIN, | |
"libya" to LIBYA, | |
"met" to MET, | |
"mst" to MST, | |
"mst7mdt" to MST7MDT, | |
"mexico/bajanorte" to MEXICO_BAJANORTE, | |
"mexico/bajasur" to MEXICO_BAJASUR, | |
"mexico/general" to MEXICO_GENERAL, | |
"nz" to NZ, | |
"nz-chat" to NZ_CHAT, | |
"navajo" to NAVAJO, | |
"prc" to PRC, | |
"pst8pdt" to PST8PDT, | |
"pacific/apia" to PACIFIC_APIA, | |
"pacific/auckland" to PACIFIC_AUCKLAND, | |
"pacific/bougainville" to PACIFIC_BOUGAINVILLE, | |
"pacific/chatham" to PACIFIC_CHATHAM, | |
"pacific/chuuk" to PACIFIC_CHUUK, | |
"pacific/easter" to PACIFIC_EASTER, | |
"pacific/efate" to PACIFIC_EFATE, | |
"pacific/enderbury" to PACIFIC_ENDERBURY, | |
"pacific/fakaofo" to PACIFIC_FAKAOFO, | |
"pacific/fiji" to PACIFIC_FIJI, | |
"pacific/funafuti" to PACIFIC_FUNAFUTI, | |
"pacific/galapagos" to PACIFIC_GALAPAGOS, | |
"pacific/gambier" to PACIFIC_GAMBIER, | |
"pacific/guadalcanal" to PACIFIC_GUADALCANAL, | |
"pacific/guam" to PACIFIC_GUAM, | |
"pacific/honolulu" to PACIFIC_HONOLULU, | |
"pacific/johnston" to PACIFIC_JOHNSTON, | |
"pacific/kanton" to PACIFIC_KANTON, | |
"pacific/kiritimati" to PACIFIC_KIRITIMATI, | |
"pacific/kosrae" to PACIFIC_KOSRAE, | |
"pacific/kwajalein" to PACIFIC_KWAJALEIN, | |
"pacific/majuro" to PACIFIC_MAJURO, | |
"pacific/marquesas" to PACIFIC_MARQUESAS, | |
"pacific/midway" to PACIFIC_MIDWAY, | |
"pacific/nauru" to PACIFIC_NAURU, | |
"pacific/niue" to PACIFIC_NIUE, | |
"pacific/norfolk" to PACIFIC_NORFOLK, | |
"pacific/noumea" to PACIFIC_NOUMEA, | |
"pacific/pago_pago" to PACIFIC_PAGO_PAGO, | |
"pacific/palau" to PACIFIC_PALAU, | |
"pacific/pitcairn" to PACIFIC_PITCAIRN, | |
"pacific/pohnpei" to PACIFIC_POHNPEI, | |
"pacific/ponape" to PACIFIC_PONAPE, | |
"pacific/port_moresby" to PACIFIC_PORT_MORESBY, | |
"pacific/rarotonga" to PACIFIC_RAROTONGA, | |
"pacific/saipan" to PACIFIC_SAIPAN, | |
"pacific/samoa" to PACIFIC_SAMOA, | |
"pacific/tahiti" to PACIFIC_TAHITI, | |
"pacific/tarawa" to PACIFIC_TARAWA, | |
"pacific/tongatapu" to PACIFIC_TONGATAPU, | |
"pacific/truk" to PACIFIC_TRUK, | |
"pacific/wake" to PACIFIC_WAKE, | |
"pacific/wallis" to PACIFIC_WALLIS, | |
"pacific/yap" to PACIFIC_YAP, | |
"poland" to POLAND, | |
"portugal" to PORTUGAL, | |
"roc" to ROC, | |
"rok" to ROK, | |
"singapore" to SINGAPORE, | |
"turkey" to TURKEY, | |
"us/alaska" to US_ALASKA, | |
"us/aleutian" to US_ALEUTIAN, | |
"us/arizona" to US_ARIZONA, | |
"us/central" to US_CENTRAL, | |
"us/east-indiana" to US_EAST_INDIANA, | |
"us/eastern" to US_EASTERN, | |
"us/hawaii" to US_HAWAII, | |
"us/indiana-starke" to US_INDIANA_STARKE, | |
"us/michigan" to US_MICHIGAN, | |
"us/mountain" to US_MOUNTAIN, | |
"us/pacific" to US_PACIFIC, | |
"us/samoa" to US_SAMOA, | |
"w-su" to W_SU, | |
"wet" to WET, | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kore.time | |
class ZoneTime( | |
val year:Int, val month:Int, val day:Int, | |
val hour:Int, val minute:Int, val second:Int, val ms:Int, val zone:Zone){ | |
companion object{ | |
operator fun invoke(saved:String):ZoneTime?{ | |
val (_, id, epoch, offset) = saved.split(":") | |
return Zone[id]?.let{ | |
UtcTime(epoch.toLong(), offset.toInt()).toZoneTime(it) | |
} | |
} | |
} | |
fun save():String = toUtcTime().let { "zt0:${zone.area}:${it.epochMs}:${it.offsetMs}"} | |
fun toString(format:TimeFormat):String = format.toString(this) | |
fun toString(format:String):String = TimeFormat(format).toString(this) | |
override fun toString():String = toString("YYYY-MM-DDTHH:mm:ss.SSS") | |
@PublishedApi internal var utcTime:UtcTime? = null | |
fun toUtcTime():UtcTime { | |
utcTime?.let { return it } | |
val epochDay = TimeUtil.epochDayFromCivil(year, month, day) | |
val wallMs = epochDay * 86_400_000L + | |
hour * 3_600_000L + | |
minute * 60_000L + | |
second * 1_000L + | |
ms | |
val periods = zone.periods | |
if (periods.size == 1 && periods[0].dstSaveSeconds == 0) { | |
val off = periods[0].stdOffsetSeconds * 1000 | |
return UtcTime(wallMs - off, off).also { utcTime = it } | |
} | |
var startUtc = Long.MIN_VALUE | |
var hasChosen = false | |
var chosenEpoch = 0L | |
var chosenOffset = 0 | |
var haveNext = false | |
var nextLocalStart = 0L | |
var nextOffset = 0 | |
val n = periods.size | |
for (i in 0 until n) { | |
val endUtcExcl = zone.endExclMs[i] | |
val offMs = zone.totalOffsetMs[i] | |
val localStart = startUtc + offMs | |
val localEnd = endUtcExcl + offMs | |
if (wallMs in localStart..<localEnd) { | |
val candidateEpoch = wallMs - offMs | |
if (!hasChosen || offMs > chosenOffset) { | |
hasChosen = true | |
chosenEpoch = candidateEpoch | |
chosenOffset = offMs | |
} | |
} else if (wallMs < localStart) { | |
if (!haveNext || localStart < nextLocalStart) { | |
haveNext = true | |
nextLocalStart = localStart | |
nextOffset = offMs | |
} | |
} | |
startUtc = endUtcExcl | |
} | |
val result = when { | |
hasChosen -> UtcTime(chosenEpoch, chosenOffset) | |
haveNext -> UtcTime(nextLocalStart - nextOffset, nextOffset) // gap | |
else -> { | |
val lastOff = zone.totalOffsetMs[n - 1] | |
UtcTime(wallMs - lastOff, lastOff) // after last period | |
} | |
} | |
return result.also { utcTime = it } | |
} | |
fun toZoneTime(otherInfo:Zone):ZoneTime = if(zone.area == otherInfo.area) this else toUtcTime().toZoneTime(otherInfo) | |
fun diffYear(other:ZoneTime):Long = diffMonth(other) / 12 | |
fun diffMonth(other:ZoneTime):Long { | |
val thisUtc = toUtcTime().toZoneTime(Zone.UTC) | |
val otherUtc = other.toUtcTime().toZoneTime(Zone.UTC) | |
return (thisUtc.year - otherUtc.year) * 12L + (thisUtc.month - otherUtc.month) | |
} | |
fun diffDay(other:ZoneTime):Long = (toUtcTime().diffDay(other.toUtcTime())) | |
fun diffHour(other:ZoneTime):Long = toUtcTime().diffHour(other.toUtcTime()) | |
fun diffMinute(other:ZoneTime):Long = toUtcTime().diffMinute(other.toUtcTime()) | |
fun diffSecond(other:ZoneTime):Long = toUtcTime().diffSecond(other.toUtcTime()) | |
fun diffMS(other:ZoneTime):Long = toUtcTime().diffMS(other.toUtcTime()) | |
private fun addCalendar(year: Int = 0, month: Int = 0): ZoneTime { | |
var newMonth = this.month + month | |
var newYear = this.year + year | |
newYear += (newMonth - 1) / 12 | |
newMonth = (newMonth - 1) % 12 + 1 | |
if (newMonth <= 0) { | |
newMonth += 12 | |
newYear-- | |
} | |
val newDay = this.day.coerceAtMost(TimeUtil.daysInMonth(newYear, newMonth)) | |
return ZoneTime(newYear, newMonth, newDay, hour, minute, second, ms, zone) | |
} | |
fun addYear(year: Int): ZoneTime = toUtcTime().toZoneTime(zone).addCalendar(year = year) | |
fun addMonth(month: Int): ZoneTime = toUtcTime().toZoneTime(zone).addCalendar(month = month) | |
fun addDay(day: Int): ZoneTime = toUtcTime().add(day = day).toZoneTime(zone) | |
fun addHour(hour: Int): ZoneTime = toUtcTime().add(hour = hour).toZoneTime(zone) | |
fun addMinute(minute: Int): ZoneTime = toUtcTime().add(minute = minute).toZoneTime(zone) | |
fun addSecond(second: Int): ZoneTime = toUtcTime().add(second = second).toZoneTime(zone) | |
fun addMS(ms: Int): ZoneTime = toUtcTime().add(ms = ms).toZoneTime(zone) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment