我想使用日历时区来设置日期对象的时区。我正在寻找合适的技术。我们在全国各地设有几个基地,每个基地都有自己的日记和日常活动日历。我们有多个发布到日历的脚本。我想使用日历的时区来设置日期对象时区,因为用户到不同的基地旅行,他们的计算机可能没有设置到正确的时区。我们希望避免错误的时间设置。
脚本的timeZone是否应设置为UTC?
这是我目前所在的地方:
function submitUiTest(e) {
var app = UiApp.getActiveApplication();
var cal = CalendarApp.getCalendarById('calendarId');
var timeZone = cal.getTimeZone();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startTime = e.parameter.startDate
startTime.setHours(e.parameter.startHour, e.parameter.startMin, 0)
startTime = formatTime(startTime, timeZone);
Logger.log(startTime)
var endTime = e.parameter.endDate
endTime.setHours(e.parameter.endHour, e.parameter.endMin, 0);
endTime = formatTime(endTime, timeZone);
Logger.log(endTime)
cal.createEvent('TimeZone Test', new Date(startTime), new Date(endTime));
ss.appendRow([startTime, endTime]);
return app;
}
function formatTime(time, timeZone){
return Utilities.formatDate(time, (timeZone-time.getTimezoneOffset()), 'M/d/yyyy HH:mm');
}
编辑: 目前有3个日历,它们不是用户日历,每个日历都是为各个空中站创建的单独日历。每个空军基地都在不同的时区。当工作人员在这些工作站工作时,他们将日常活动发布到日历,并且我们也有几个Ui脚本发布到相同的日历中。飞行日志。当日历的条目发布到任何日历时,时间仅与脚本上设置的时区相关,而不是日历上的时区。创建日期或时间戳对象时,如何使用日历本身设置的时区。
记录不同时区日期的脚本的最佳做法是什么? 将脚本时区设置为UTC并进行转换? 您使用什么来获取用户的时区,或者在这种情况下,我不关心用户的时区设置是什么,我需要使用日历的时区。
答案 0 :(得分:4)
以下是答案的修改版本,没有UI内容:
function gasTimezoneOffset(date, hour){
var cal,calTimeZone,calTz,date,dateString,scriptTimeZone,sessionTz;
var testMonth = "March",
testDayOfMnth = "26",
testYr = "2016",
hour = "10:00",
timeZoneDiff = 0;
Logger.log("Script Time Zone: " + Session.getScriptTimeZone());
dateString = testMonth + " " + testDayOfMnth + ", " + testYr;
Logger.log("dateString: " + dateString);
date = new Date(dateString);
cal = CalendarApp.getDefaultCalendar();
calTimeZone = cal.getTimeZone();
calTimeZone = Utilities.formatDate(date, calTimeZone, 'Z');
scriptTimeZone = Utilities.formatDate(date, Session.getTimeZone(), 'Z');
calTz = Number(calTimeZone.slice(0,3));
sessionTz = Number(scriptTimeZone.slice(0,3));
//If both time zones are the same sign, get the difference between the
//two. E.g. -4 and -2. Difference is 2
//if each time zone is a different sign, add the absolute values together.
//-4 and +1 should be 5
if (calTz < 0 && sessionTz > 0 || calTz > 0 && sessionTz < 0){
timeZoneDiff = Math.abs(Math.abs(calTz) + Math.abs(sessionTz));
} else {
timeZoneDiff = Math.abs(Math.abs(calTz) - Math.abs(sessionTz));
};
hour = Number(hour.slice(0,2));
return hour + timeZoneDiff;
};
答案 1 :(得分:1)
编辑:我写了一个小测试用户界面并在2个不同的时区中使用2个日历运行它。 日历事件在日历时区中创建,用户界面显示用户值。 Google负责两个日历中的时区设置,但我没有注意到任何异常情况:按照我的意愿创建的事件,即日历时区的UI中显示的时间。
(截屏)
以下是我用于测试的代码:
var tz = [['test_agenda(pacific Time)','test_agenda'],['testencodage(Belgium time)','testencodage']]
function doGet() {
var app = UiApp.createApplication().setStyleAttribute('padding','15PX');
var hpanel = app.createHorizontalPanel();
var dateBox = app.createDateBox().setId('dateBox').setName('dateBox');
var hour = app.createListBox(false).setId('hour').setName('hour')
for(h=0;h<25;++h){
if(h/2==parseInt(h/2)){hour.addItem(parseInt(h/2)+':00')
}else{
hour.addItem(parseInt(h/2)+':30')
}
}
var amPm = app.createListBox(false).setId('am').setName('amPm')
.addItem('AM').addItem('PM');
var dateTimeLabel = app.createLabel('',false).setId('dateTimeLabel');
var submit = app.createButton('Submit').setId('submit');
var tzList = app.createListBox().setName('tzList');
for(var c in tz){tzList.addItem(tz[c][0],tz[c][1])}
var handler1 = app.createClientHandler().validateMatches(dateBox, '2','g').forEventSource().setEnabled(false);
var handler2 = app.createServerHandler('createE').validateMatches(dateBox, '2','g').addCallbackElement(hpanel).addCallbackElement(tzList);
submit.addClickHandler(handler1).addClickHandler(handler2);
hpanel.add(dateBox).add(hour).add(amPm)
app.add(hpanel);
app.add(tzList).add(submit);
app.add(dateTimeLabel);
return app;
}
function createE(e) {
var app = UiApp.getActiveApplication();
var date = e.parameter.dateBox;
var cal = CalendarApp.getCalendarsByName(e.parameter.tzList)[0]
var timeZone = cal.getTimeZone();
var sessionTz = Session.getTimeZone()
Logger.log(sessionTz)
Logger.log(timeZone)
var hour = Number(e.parameter.hour.split(':')[0]);
var min = Number(e.parameter.hour.split(':')[1]);
var amPm = e.parameter.amPm;
if (amPm == 'PM' ){hour = hour+12}; // ADD 12 HOURS TO PM HOURS, EXCEPT 12PM
if (hour == 24){hour = 0;amPm='AM'}; // HANDLE 12AM HOUR CORRECTLY
var newDate=new Date(date)
newDate.setHours(hour,min,0,0)
Logger.log('start : '+newDate)
var newDateString = Utilities.formatDate(newDate, sessionTz, 'MM/dd/yyyy hh:mm aaa');
app.getElementById('dateTimeLabel').setText('tz = '+timeZone+' - '+newDateString);
Logger.log('end : '+new Date(newDate.getTime()+3600000))
cal.createEvent('test Event in TZ '+timeZone, newDate, new Date(newDate.getTime()+3600000))
app.getElementById('submit').setEnabled(true);
return app;
}
第一条评论:
我开始写评论问你一些问题但是时间太长了......所以请把它当作评论,而不是答案;-)。 我不确定我理解你所说的“他们的计算机没有被设置到正确的时区”,如果他们使用谷歌日历,他们的计算机的时区是不相关的,这只是Google Cal的参数问题。如果我明白你的目标是,如果脚本在上午8点设置预约,他们将在上午8点在他们的日历中看到它显示在任何地方(在他们的“本地”时区的上午8点),对吗?登记/> 总而言之,您从一个地方运行此脚本,并在自己的日历中为其他时区的人员创建事件?用户是否跨越不同的时区?这是两个单独的问题,它没有一个单一的解决方案。 如果单个用户跨时区移动,除非他不改变他的GCal参数,否则所有事件都将被移动。但是,如果他这样做,他将不会在正确的时间得到通知,日历界面将没有时间......所以这不是一个合理的解决方案。 我的最后一个问题:当你在另一个日历中创建一个事件(在另一个日历中)时,你和这个人之间可以约会吗?换句话说,对你使用案例的绝对时间是什么重要的?
答案 2 :(得分:1)
好的,这是问题的解决方案。我可能已经离开了我的方式或错过了一些简单的东西,但这终于像我希望的那样工作。随意批评。为简单起见,我将webapp时区设置为GMT-0000。
function uiTest() {
var app = UiApp.createApplication();
var startDate = app.createDateBox().setName('startDate').setId('startDate').setWidth('75');
var startHour = app.createListBox().setName('startHour').setId('startHour').setWidth('45');
var startMin = app.createListBox().setName('startMin').setId('startMin').setWidth('45');
var endDate = app.createDateBox().setName('endDate').setId('endDate').setWidth('75');
var endHour = app.createListBox().setName('endHour').setId('endHour').setWidth('45');
var endMin = app.createListBox().setName('endMin').setId('endMin').setWidth('45');
for (h=0;h<24;++h){
if(h<10){
var hourstr='0'+h
}else{
var hourstr=h.toString()
}
startHour.addItem(hourstr)
endHour.addItem(hourstr)
}
for (m=0;m<60;++m){
if(m<10){
var minstr='0'+m
}else{
var minstr=m.toString()
}
startMin.addItem(minstr)
endMin.addItem(minstr)
}
var grid = app.createFlexTable().setId('grid');
app.add(grid);
grid.setWidget(0, 0, app.createLabel('Start Date'));
grid.setWidget(1, 0, startDate);
grid.setWidget(0, 1, app.createLabel('Hour'));
grid.setWidget(1, 1, startHour);
grid.setWidget(0, 2, app.createLabel('Min'));
grid.setWidget(1, 2, startMin);
grid.setWidget(2, 0, app.createLabel('End Date'));
grid.setWidget(3, 0, endDate);
grid.setWidget(2, 1, app.createLabel('Hour'));
grid.setWidget(3, 1, endHour);
grid.setWidget(2, 2, app.createLabel('Min'));
grid.setWidget(3, 2, endMin);
app.add(app.createButton('Submit', app.createServerHandler('submitUiTest').addCallbackElement(grid)));
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function submitUiTest(e) {
var app = UiApp.getActiveApplication();
var cal = CalendarApp.getCalendarById('');//Info Sys Calendar set to Central Time
//var cal = CalendarApp.getCalendarById('');//Fort Bliss (Mountain Time)
var calTimeZone = cal.getTimeZone();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startTime = e.parameter.startDate
startTime.setHours(gasTimezoneOffset(startTime, e.parameter.startHour, calTimeZone), e.parameter.startMin, 0);
Logger.log('startTime: '+Utilities.formatDate(startTime, calTimeZone, 'M/d/yyyy HH:mm z'));
var endTime = e.parameter.endDate
endTime.setHours(gasTimezoneOffset(endTime, e.parameter.endHour, calTimeZone), e.parameter.endMin, 0);
Logger.log('endTime: '+endTime)
var timeStamp = Utilities.formatDate(startTime, calTimeZone, 'M/d/yyyy HH:mm z');
cal.createEvent(timeStamp, new Date(startTime), new Date(endTime));
ss.appendRow([startTime, endTime]);
return app;
}
function gasTimezoneOffset(date, hour, calTimeZone){
var calTz = new Number(Utilities.formatDate(date, calTimeZone, 'Z').substr(1,2));
var sessionTz = new Number(Utilities.formatDate(date, Session.getTimeZone(), 'Z').substr(1,2));
switch (Utilities.formatDate(date, calTimeZone, 'Z').substring(0,1)){
case '+':
var timeZoneOffset = sessionTz - calTz;
break;
case '-':
var timeZoneOffset = sessionTz + calTz;
break;
}
hour = new Number(hour);
return hour + timeZoneOffset;
}
答案 3 :(得分:1)
这是Sandy的代码版本,我最终使用它来创建一个获取Calendar对象和“脚本时间”并返回“日历时间”的函数:
/**
* Given a script date object, return the time in the user's calendar
*
* Sandy Good's answer to this SO question:
*
* http://stackoverflow.com/questions/15645343/how-to-use-timezone-of-calendar-to-set-timezone-for-date-object
*
* @param {Date} scriptDateTime
* @param {Calendar} calendar
*
* @return {Date} calendarDateTime
*/
function getCalendarDateTime (scriptDateTime, calendar) {
Logger.log('scriptDateTime: ' + scriptDateTime)
var calendarTimeZoneString = calendar.getTimeZone()
var calendarTimeZone = Utilities.formatDate(scriptDateTime, calendarTimeZoneString, 'Z')
var calendarTz = Number(calendarTimeZone.slice(0,3))
Logger.log('calendarTimeZone: %s (%s)', calendarTimeZoneString, calendarTz)
var scriptTimeZoneString = Session.getScriptTimeZone()
var scriptTimeZone = Utilities.formatDate(scriptDateTime, scriptTimeZoneString, 'Z')
var sessionTz = Number(scriptTimeZone.slice(0,3))
Logger.log('scriptTimeZone: %s (%s)', scriptTimeZoneString, sessionTz)
// If both time zones are the same sign, get the difference between the
// two. E.g. -4 and -2. Difference is 2
//
// If each time zone is a different sign, add the absolute values together.
// -4 and +1 should be 5
var timeZoneDiff
if (calendarTz < 0 && sessionTz > 0 || calendarTz > 0 && sessionTz < 0) {
timeZoneDiff = Math.abs(Math.abs(calendarTz) + Math.abs(sessionTz))
} else {
timeZoneDiff = Math.abs(Math.abs(calendarTz) - Math.abs(sessionTz))
}
Logger.log('timeZoneDiff: ' + timeZoneDiff)
var scriptHour = scriptDateTime.getHours()
var calendarHour = scriptHour + timeZoneDiff
var calendarDateTime = new Date(
scriptDateTime.getYear(),
scriptDateTime.getMonth(),
scriptDateTime.getDate(),
calendarHour,
scriptDateTime.getMinutes())
Logger.log('calendarDateTime: ' + calendarDateTime)
return calendarDateTime
}
// Script is PST (GMT-8) and calendar is GMT
function test_getCalendarDateTime() {
var calendar = CalendarApp.getDefaultCalendar()
var scriptDateTime = new Date(2017, 0, 30, 12, 0) // 2017-01-30 12:00 PST
var calendarDateTime = getCalendarDateTime(scriptDateTime, calendar) // 2017-01-30 20:00 PST
}
答案 4 :(得分:0)
可以尝试为每个时区部署单独的Web应用程序。将每个应用的时区设置为与其链接的唯一日历的时区相匹配。由于您在不同的时区只有3个日历,所以看起来它适用于您的情况。