使用 DST 设置获取 JavaScript 时区字符串

Posted

技术标签:

【中文标题】使用 DST 设置获取 JavaScript 时区字符串【英文标题】:Get JavaScript timezone string with DST settings 【发布时间】:2020-04-08 08:15:30 【问题描述】:

上下文

我在 ESP8266 上运行 Web 服务器,并希望在设备上实现自动 DST。目前我正在从客户端获取时间设置。我使用的是 ESP8266 SDK 而不是 Arduino。

信息流

网络服务器没有互联网连接,只有 WiFi。

|Web 服务器||WiFi||客户端||互联网|

打算如何发送 TZ 字符串。

|网络服务器|

客户端可以是任何可以运行现代浏览器的东西。

问题

有没有办法使用 javascript 从客户端获取以下格式的 DST 设置?

std offset dst [offset],start[/time],end[/time]

我可以使用以下方法获取时区字符串:

Intl.DateTimeFormat().resolvedOptions().timeZone

我正在使用的当前系统不支持该格式。

:字符

Witch 是上述 JavaScript 返回的格式。如果我没记错的话。

代码

time_t now =0;
struct tm timeinfo;
setenv("TZ","IST-2IDT,M3.5.5/2,M10.5.0/2", 1);
tzset();

timeinfo.tm_sec =   sec;
timeinfo.tm_min =   min;
timeinfo.tm_hour =  hour;
timeinfo.tm_mday =  date;
timeinfo.tm_mon =   mon;
timeinfo.tm_year =  year + 100;
timeinfo.tm_wday =  weekd;

//set the time manually
now = mktime(&timeinfo);

if(now < 0)
 //handle error
 ESP_LOGE(__func__, "Time error");

else
 localtime_r(&now, &timeinfo);
 //print tm_isdst value
 ESP_LOGW(__func__, "DST is active %d",timeinfo.tm_isdst);

 char strftime_buf[64];
 strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
 //print time str
 ESP_LOGI(__func__, "The current date/time: %s", strftime_buf);

问题

如果我使用 IST-2IDT,M3.5.5/2,M10.5.0/2 设置 TZ 验证,timeinfo.tm_isdst 变量会在预期的日期和时间发生变化。如果我用Asia/Jerusalem 设置TZ,timeinfo.tm_isdst 变量只会保持在0。也用America/New_York 进行测试,结果相同。

参考

TZ-Variable

Almost Identical Use Case

我不使用“Almost Identical Use Case”的原因是我的内存和存储空间严重不足,无法在 Web 服务器上存储大型 C 字符串。

【问题讨论】:

为什么要知道是不是夏令时? tz database 提供历史信息,所以Asia/JerusalemAmerica/New_Yorkstd offset dst [offset],start[/time],end[/time] 好得多,std offset dst [offset],start[/time],end[/time] 仅在“现在”有效。时区信息一直在变化(并且会继续发生,看看很多地方是如何摆脱 DST 的)。 @ikegami。它概括了多个区域的代码(简而言之)。如果我可以使用Asia/JerusalemAmerica/New_York 形成tz 数据库字符串,我会但正如我所说,当我将字符串提供给Web 服务器(ESP8266)时,它会被忽略(就像没有时区字符串一样)。这个想法是使用最有可能具有最新 dst 设置的桌面/服务器客户端来设置设备。如果时区信息发生变化,那么用户/客户端将不得不再次传递数据。 你似乎没有抓住重点。没有“最新的 dst settings”(假设您的意思是 std offset dst [offset],start[/time],end[/time] 用于设置),因为该设置取决于应用它的日期时间的年份。 更重要的一点是,您应该添加对 tz 数据库的支持,而不是尝试从 tz 数据库名称中获取“设置”。 【参考方案1】:

最可靠的解决方案是将时间作为纪元时间戳发送,并使用 JavaScript 将其转换为本地时间。


也就是说,如果您安装了tz database 的副本,则每个区域文件的最后一次是一个 POSIX TZ 字符串(可能为空)。

当然,您不能指望它对于与当年不同年份的日期是准确的,但它似乎是您想要的。

$ tail -n 1 /usr/share/zoneinfo/Asia/Jerusalem
IST-2IDT,M3.4.4/26,M10.5.0

$ tail -n 1 /usr/share/zoneinfo/America/New_York
EST5EDT,M3.2.0,M11.1.0

db 的大小约为 3.5 MiB,但您可以轻松提取所需的信息,然后再将其放置在设备上。以下产生约 60 KiB 的输出。

perl -e'
   use strict;
   use warnings;
   use feature qw( say );

   use File::Find::Rule    qw( );
   use IPC::System::Simple qw( capturex );

   my ($db) = @ARGV
     or die("usage\n");

   for my $tz (File::Find::Rule->relative->file->in($db)) 
      my $posix = capturex("tail", -n => 1, "--", "$db/$tz");
      chomp($posix);
      say join "\t", $tz, $posix;
   
' /usr/share/zoneinfo

【讨论】:

3.5Mb 太大。在总共 4Mb 的那一刻,只剩下 2Mb 的空闲空间。我在微控制器上。是的,tail 输出正是我想要的。

以上是关于使用 DST 设置获取 JavaScript 时区字符串的主要内容,如果未能解决你的问题,请参考以下文章

在python中获取给定时区的DST边界

获取节点中特定时区的 UTC 偏移量和 DST 信息? [复制]

如何将用户的本地时间转换为多伦多时区,然后在 Javascript 中根据多伦多时间检查 dst?

时刻时区和 DST

DST所指的时区是什么?

当时区有 dst 更新时,我如何安排活动