我正在寻找一种方法,将标准 UTC 时间戳转换为本地时区的有效日期时间值,并考虑夏令时振荡。
...使用这个未命名的日历应用程序,它没有设置自定义时区的选项,因此所有事件都以 UTC 格式记录,但由本地时区 + 夏令时进行偏移。
例如:生日聚会是
20/02/2023 00:00:00
但 UTC 时间戳为 20230219T220000Z
,因此任务是将其转换为“真正的”可读格式,例如:
来自 UTC | 到日期时间 |
---|---|
20230219T220000Z | 2023年2月20日00:00:00 |
20230519T210000Z | 20/05/2023 00:00:00 |
20240901T210000Z | 2024/02/09 00:00:00 |
20230313T070000Z | 13/03/2023 09:00:00 |
20230403T050000Z | 2023年3月4日08:00:00 |
20230815T113000Z | 2023年8月15日14:30:00 |
快速搜索产生了几个问题(像这个),但没有一个答案解决夏令时方面,同时在公式执行范围内发生从UTC到
dd/mm/yyyy
的转换
夏令时的做法很棘手,可能取决于各种因素(官方、地区、当地、习俗...),甚至标准 DST 也可能在转换的时间和方式上有多种变化(在某些国家/地区是每年的第二个星期日) 11 个月,在其他月份,它可以是第 1 个月、第 4 个月或最后一个月 - 当该月只有 3 或 5 天时),因为这个星球上有 100 多个独特的版本,并且结合了 38 个时区,在转换过程中可能会丢失无数的错误。因此,将其硬编码(一种变体)到公式中是没有意义的。更好的解决方案包括一个可以承载转换逻辑的边桌,例如:
其中字段包含以下数据验证规则:
1,2,3,4,5,6,7,8,9,10,11,12
1st,2nd,3rd,4th,last
mon,tue,wed,thu,fri,sat,sun
hh:mm:ss
格式,也可以是数字时间值格式。 FX:=(F6<=0.999999994)*(F6>=0)
-hh:mm:ss
格式,也可以是数字时间值格式。 FX:=(F11<=0.999999994)*(F11>=-0.999999994)
由此,我们可以使用以下数组公式找到任何(合理)年份的夏令时转换的日期时间值:
=INDEX(IFERROR(BYROW(A3:A30, LAMBDA(i, LET(p, "select max(Col1) group by Col1 pivot Col2",
d, YEAR(i)&"-"&F3, e, EOMONTH(d, ), s, SEQUENCE(e-d+1, 1, d*1), t, TEXT(s, "ddd"),
IF(REGEXMATCH(F4, "^[2-4]"), VLOOKUP(F5, SPLIT(FLATTEN(QUERY(QUERY({s, t}, p),,49)), " "),
LEFT(F4, 1)+1, ), XLOOKUP(F5, t, s,,,IF(F4="last", -1, 1)))+N(F11)+N(F6))))))
其中 XLOOKUP 处理第一个和最后一个状态,其余部分由 VLOOKUPing 数据透视表处理
=INDEX(IF(A3:A30="",,REGEXREPLACE(A3:A30,
"(....)(..)(..)(.)(..)(..)(..)(.)", "$1-$2-$3 $5:$6:$7")*1))
=INDEX(IF(B3:B30="",,TEXT(B3:B30, "yyyymmdd\Thhmmss\Z")))
为此,我们结合上面的所有内容并添加两个字段
并使用这个公式:
=INDEX(IFERROR(BYROW(A3:A27, LAMBDA(i, LET(p, "select max(Col1) group by Col1 pivot Col2",
d, LEFT(i, 4)&"-"&F3, e, EOMONTH(d, ), s, SEQUENCE(e-d+1, 1, d*1), t, TEXT(s, "ddd"),
f, IF(REGEXMATCH(F4, "^[2-4]"), VLOOKUP(F5, SPLIT(FLATTEN(QUERY(QUERY({s, t}, p),,49)), " "),
LEFT(F4, 1)+1, ), XLOOKUP(F5, t, s,,,IF(F4="last", -1, 1)))+N(F11)+N(F6),
д, LEFT(i, 4)&"-"&F7, е, EOMONTH(д, ), с, SEQUENCE(е-д+1, 1, д*1), т, TEXT(с, "ddd"),
ф, IF(REGEXMATCH(F8, "^[2-4]"), VLOOKUP(F9, SPLIT(FLATTEN(QUERY(QUERY({с, т}, p),,49)), " "),
LEFT(F8, 1)+1, ), XLOOKUP(F9, т, с,,,IF(F8="last", -1, 1)))+N(F11)+N(F10),
x, REGEXREPLACE(i, "(....)(..)(..)(.)(..)(..)(..)(.)", "$1-$2-$3 $5:$6:$7")*1,
IF((x>f)*(x<ф), x+F13, x+F12))))))
然后返回:
=INDEX(IFERROR(BYROW(B3:B27, LAMBDA(i, LET(p, "select max(Col1) group by Col1 pivot Col2",
d, YEAR(i)&"-"&F3, e, EOMONTH(d, ), s, SEQUENCE(e-d+1, 1, d*1), t, TEXT(s, "ddd"),
f, IF(REGEXMATCH(F4, "^[2-4]"), VLOOKUP(F5, SPLIT(FLATTEN(QUERY(QUERY({s, t}, p),,49)), " "),
LEFT(F4, 1)+1, ), XLOOKUP(F5, t, s,,,IF(F4="last", -1, 1)))+N(F11)+N(F6),
д, YEAR(i)&"-"&F7, е, EOMONTH(д, ), с, SEQUENCE(е-д+1, 1, д*1), т, TEXT(с, "ddd"),
ф, IF(REGEXMATCH(F8, "^[2-4]"), VLOOKUP(F9, SPLIT(FLATTEN(QUERY(QUERY({с, т}, p),,49)), " "),
LEFT(F8, 1)+1, ), XLOOKUP(F9, т, с,,,IF(F8="last", -1, 1)))+N(F11)+N(F10),
TEXT(IF((i>f)*(i<ф), i-F13, i-F12), "yyyymmdd\Thhmmss\Z"))))))
对于其他转换,请遵循:
1d 2h 3m 4s
转换为持续时间