如何在启用Luxon的Google Apps Script项目中填充时区支持?

huangapple go评论70阅读模式
英文:

How to polyfill timezone support into a Luxon-enabled Google Apps Script project?

问题

尝试为启用了Luxon的Google Apps Script项目添加时区支持。

我正在开发一个小型的Google Apps Script,以便能够创建一个包含一些时区和本地时区(从最终用户的角度看)的Google表格。类似于这样(如果用户位于伦敦):

如何在启用Luxon的Google Apps Script项目中填充时区支持?

用户位置的时区将由脚本自动检测,并由一个函数返回以填充E2单元格。E3和E4单元格将由手动填写标准的IANA时区名称,并且脚本中的另一个函数(例如,"=TIME_AT(E4)",例如,在F4处)将返回东京的当前时间。

请注意,我需要使用IANA字符串,尽管不同时间的计算可以通过偏移量完成。我的意思是,用户可以随着世界各地组织的新分支的创建而向表格添加新行(E列验证将设置为仅允许来自IANA时区名称列表的值)。

为了做到这一点,我决定利用Luxon,它支持时区,但我在使一切正常工作方面遇到了一些困难。

我首先在我的Google Apps项目中创建了一个文件,命名为luxon.js.gs,并复制粘贴了整个luxon库的代码。然后,根据Luxon时区手册的说明,我尝试检查运行时是否支持IANA时区:

luxon.Info.features()

唯一返回的功能是"relative"。因此,再次根据Luxon的时区文档,我尝试根据这里的说明“polyfill”时区支持。它将我带到了formatjs的https://github.com/formatjs/date-time-format-timezone页面。但是从那里我不确定该怎么做。我尝试将js文件复制粘贴到项目中,但当我尝试像上面那样检查luxon.Info.features时,我得到了这个错误:

12:11:08PM	Error	
ReferenceError: window is not defined
(anonymous)	@ date-time-format-timezone-complete-min.js.gs:74
7../code/data-loader.js	@ date-time-format-timezone-complete-min.js.gs:74
e	@ date-time-format-timezone-complete-min.js.gs:1
a	@ date-time-format-timezone-complete-min.js.gs:1
(anonymous)	@ date-time-format-timezone-complete-min.js.gs:1

我没有完全理解这意味着什么,但这是否意味着我无法进行这种“polyfill”,因为运行时不是浏览器运行时?如果是这样,如何解决?

谢谢。

英文:

Trying to polyfill timezone support into a Luxon-enabled Google Apps Script project.

I am developing a small Google Apps Script to be able to create a Google sheet with a table that will include some time zones and the local timezone (as seen from the end-user standpoint). Something like this (should the user be located in London):

如何在启用Luxon的Google Apps Script项目中填充时区支持?

The idea that the user's location timezone would be automatically detected by the script, and returned by a function to populate the E2 cell. The E3 and E4 cells would be filled by hand with standard IANA timezone names, and another function in the script (say, "=TIME_AT(E4)", for example, at F4, would return the current time in Tokyo).

Please note that I need to work with the IANA strings, although the calculations for the different times could be done by offset. What I mean by that is that a user could perhaps add new lines to the sheet as new branches of the organization are created around the world (the E column validation will be set to only allow values from the IANA tz names list).

To do this, I decided to leverage Luxon, which has timezones support, but I am having a bit of trouble to make everything work.

I started by creating a file in my Google Apps project, named it luxon.js.gs, and copy-pasted all of the luxon library code. Then, following the instructions from the Luxon timezone manual, I tried to check whether the runtime supported IANA timezones with:

luxon.Info.features()

The only feature returned was "relative". So, once again following the timezone documentation from Luxon, I tried to "polyfill" the timezone support following the instructions here. It led me to the formatjs https://github.com/formatjs/date-time-format-timezone page. But from there I am not sure what to do. I tried to copy-paste the js file into the project, but when I tried to check for the luxon.Info.features as above I got this:

12:11:08 PM	Error	
ReferenceError: window is not defined
(anonymous)	@ date-time-format-timezone-complete-min.js.gs:74
7../code/data-loader.js	@ date-time-format-timezone-complete-min.js.gs:74
e	@ date-time-format-timezone-complete-min.js.gs:1
a	@ date-time-format-timezone-complete-min.js.gs:1
(anonymous)	@ date-time-format-timezone-complete-min.js.gs:1

I didn't get exactly what that means, but does it mean that I cannot do this polyfilling because the runtime is not a browser one? If so, how to solve it?

Thank you.

答案1

得分: 1

I'll provide the translation of the code part you requested:

function myFunction() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const [base, ...values] = sheet.getRange("E2:F" + sheet.getLastRow()).getValues();
  const b = base[1];
  const res = values.map(([e]) => [new Date(Utilities.formatDate(b, e, "yyyy-MM-dd'T'HH:mm:ss"))]);
  sheet.getRange(3, 6, res.length).setValues(res).setNumberFormat("hh:mm");
}

If you need further translations or assistance, please let me know.

英文:

I believe your goal is as follows.

  • In your Spreadsheet, your current time is put into the cell "F2".
    • Unfortunately, I cannot know whether your value of "F2" is the date object. So, in this answer, I suppose that the value of "F2" is the date object like =NOW(). Please be careful about this.
  • The cells "E2:E" has the valid timezones of IANA.
  • You want to retrieve the cells "E2:E", and want to convert your current time and put in column "F" using the timezone and the value of "F2".

I thought that in your situation, formatDate(date, timeZone, format) might be able to be used. When this is used, how about the following sample script?

Sample script 1:

In this sample, it supposes that the cell "F2" is the date object.

function myFunction() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const [base, ...values] = sheet.getRange("E2:F" + sheet.getLastRow()).getValues();
  const b = base[1];
  const res = values.map(([e]) => [new Date(Utilities.formatDate(b, e, "yyyy-MM-dd'T'HH:mm:ss"))]);
  sheet.getRange(3, 6, res.length).setValues(res).setNumberFormat("hh:mm");
}
  • When this script is run, the converted values are put into cells "F2:F".

Sample script 2:

In this sample, it supposes that the cell "F2" is the string.

function myFunction() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const [base, ...values] = sheet.getRange("E2:F" + sheet.getLastRow()).getDisplayValues();
  const b = Utilities.parseDate(new Date().toISOString().split("T")[0] + base[1], base[0], "yyyy-MM-ddHH:mm");
  const res = values.map(([e]) => [Utilities.formatDate(b, e, "HH:mm")]);
  sheet.getRange(3, 6, res.length).setValues(res).setNumberFormat("hh:mm");
}
  • When this script is run, the converted values are put into cells "F2:F".

  • In this script, if you want to put the values to column "F" as the date object including year, month, and day, please modify as follows.

    • From

        const res = values.map(([e]) => [Utilities.formatDate(b, e, "HH:mm")]);
      
    • To

        const res = values.map(([e]) => [new Date(Utilities.formatDate(b, e, "yyyy-MM-dd'T'HH:mm:ss"))]);
      

Note:

  • When I tested these scripts using the situation of your provided sample Spreadsheet image, I confirmed that a value of 16:56 with Europe/London is converted to 11:56 and 00:56 for America/New_York and Asia/Tokyo, respectively.
  • This sample script is for the Spreadsheet of your showing image. When you change the Spreadsheet, this script might not be able to be used. Please be careful about this.

References:

Added:

From your following reply,

> Would it be possible to create a formula like "function TO_TIMEZONE(time, timezone)" that could be used in each result cell, referring to the cell that has the current time and the cell that has the target timezone?

How about the following sample script?

const TO_TIMEZONE = (time, timezone) =>
  new Date(Utilities.formatDate(time, timezone, "yyyy-MM-dd'T'HH:mm:ss"));
  • In this case, when your showing sample image is used, please put a custom function like =TO_TIMEZONE($F$2,E3) and =TO_TIMEZONE($F$2,E4) into cell "F3" and "F4", respectively. By this, when "F2" is 16:56 as the date object, 11:56 and 00:56 are obtained.
  • Although, unfortunately, I cannot still understand whether your cell value of "F2" is the date object, in this sample, it supposes that "F2" is the date object. Please be careful about this.

huangapple
  • 本文由 发表于 2023年5月30日 00:19:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76358870.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定