Moment.js time wrong when DST is on - momentjs

Don't understand why the examples on moment-timezone page give me different result than what they say they should.
Running these statements give me date with my current local time for each instance:
var jun = moment("2014-06-01T12:00:00Z");
var dec = moment("2014-12-01T12:00:00Z");
jun.tz('America/Los_Angeles').format('ha z'); // 5am PDT **I get 7am**
dec.tz('America/Los_Angeles').format('ha z'); // 4am PST **I get 6am**
What am I missing?

Found the issue was due to missing time zone data. After loading time zone data I get the expected results, below; how to load time zone data
[http://momentjs.com/timezone/docs/#/data-loading/][1]

Related

moment object gives different date when formatted

formatting a moment object gives me a different result to the one I expect to see
I tried removing UTC but still don't get the result i expect
moment.utc().startOf("day").subtract(schedule.pastDays, "days")
returns date object with:
_d: Wed Jul 17 2019 00:00:00 GMT+0000 (Etc Greenwich Standard Time) {}
but formatting it:
moment.utc().startOf("day").subtract(schedule.pastDays, "days").format()
returns:
"2019-07-16T22:00:00Z"
Where did the 2hrs go that kicked the date back to the previous day?
I expected to see:
"2019-07-17T00:00:00Z" as the date object would suggest.
So if I do not specify a timezone, moment presumes utc and so adjusts when I format(). This however works and keeps the formatted time local:
var tzDay = moment().utcOffset(moment().utcOffset(), true).local()
var newDay = tzDay.format('MMDDYYYY');
console.log(newDay)
//returns today's date without any utc adjustment

BlueSky Statistics - String to date [time] issues

Trying to convert time as a string to a time variable.
Use Date/Dates/Convert String to Date...... for format I use %H:%M:%S....
Here is the syntax from the GUI
[Convert String Variables to Date]
BSkystrptime (varNames = c('Time'),dateFormat = "%H:%M:%S",prefixOrSuffix = "prefix",prefixOrSuffixValue = "Con_",data = "Dataset2")
BSkyLoadRefreshDataframe(dframe=Dataset2,load.dataframe=TRUE)
A screen shot of result is attached....
Compare variables Time [string] to Con_Time [date/time]
The hours are 2 hours out [wrong!] - the Minutes and Seconds are correct.
What am I doing wrong here?
Screen Shot
I believe you are running into a known issue with a prior release of BlueSky Statistics. This issue is fixed with the current stable release available on the download page.
The reason for this was although the time is converted correctly into the local time zone, BlueSky Statistics was reading the time zone in the local time zone and converting it to UTC.
You are probably +2 hours ahead of UTC, so you are seeing the time move 2 hrs back. Give us a couple of days to post a patch.
You can also confirm this by writing and executing the following syntax in the syntax window
Dataset2$Con_Time

splunk mysearchbar.timerange.val() datetime to UTC

I am using Splunk 6.2.X along with Django bindings to create a Splunk app.
To get access to the earliest/latest dates from the timerange picker, am using the following in my JS.
mysearchbar.timerange.val()
Am getting back a map where the values are in epoch format:
Object {earliest_time: 1440122400, latest_time: 1440124200}
When I convert them using moment using the following, I get different datetime than expected:
> moment.unix('1440122400').utc().toString()
"Fri Aug 21 2015 02:00:00 GMT+0000"
However, the time does not correspond to the values that have been selected on the time range picker i.e. 08/20/2015 22:00:00.000
Am not sure what the difference is getting caused by? Am sure tht the timezone is not the factor as the time difference is erratically not equivalent to derive using simple timezone add/subtract.
I was wondering if this behaviour can be explained as to how to get the Splunk epoch datetime to UTC would be helpful.
I was able to get rid of the timezone issue by performing the following:
Setting the timezone of the Splunk engine to UTC in props.conf as follows:
TZ = GMT
Setting up the CentOS (the server hosting Splunk) to UTC
Hope this helps anyone else who stumbles upon similar issues.
Thanks.

Getting local time for future events based off UTC

I'm working on a script that will look up an event on a community Google Calendar (using Eastern Time Zone) and successfully convert it to the local user's timezone. Because it is a community Google Calendar, I cannot set the time to display as UTC, which would theoretically make this that much easier. Here is a step-by-step process that I am attempting to create:
Get the event time as it stands (Eastern time) from Google Calendar. This is done quite easily using the API and json format.
Get the Eastern timezone offset based on the event time using Google Maps API. Again, this is easily done.
Convert the Event time from Eastern to UTC, which I believe is done by adding the offset to the Event time.
Calculate the local timezone/UTC timezone difference based on the future date.
Return the local time for the event by adding step 4's result to the UTC event's time.
However, no matter what I do, it seems to not work the way I want it. Here is the code as it stands:
local function get_local_time(dateTime)
local xyear, xmonth, xday = string.match(dateTime, "(%d+)%-(%d+)%-(%d+)") -- Date format is displayed as yyyy-mm-dd
local xhour, xmin = string.match(dateTime, "%a(%d+):(%d+)") -- Time format is displayed as Thh:mm
local event_time = os.time({year = xyear, month = xmonth, day = xday, hour = xhour or 23, min = xmin or 59, sec = 0}) -- Gets epoch time for event time
async_ok, async = pcall (require, "async") -- Asynchronous lookup functions
if not json then json = require 'json' end
tzpage = "https://maps.googleapis.com/maps/api/timezone/json?location=28.4158,-81.2989&timestamp=" .. event_time .. "&key=" .. key -- Gets offset data for Eastern Time Zone
if async_ok then
tzrpage = async.request(tzpage, "HTTPS")
end
retval, page, status, headers, full_status = tzrpage:join()
tzrpage = nil
if status == 200 then
tzopage = json.decode(page)
end
local eastern_offset = tzopage.rawOffset+tzopage.dstOffset -- Adds the offset information together (includes Daylight Savings)
local utc_event_time = event_time+eastern_offset -- Sets UTC's time for the event
local utctime, localtime = os.date("!*t", utc_event_time), os.date("*t", utc_event_time) -- Sets table data for events based on UTC's time of the event
localtime.isdst = false
local localoffset = os.difftime(os.time(utctime), os.time(localtime)) -- Sets the time difference between UTC and local time at the time of the event UTC
return os.date("%A, %B %d %Y at %I:%M%p", (utc_event_time-localoffset)) -- Should return local time of the event
end
But when I do something like the following:
print(get_local_time("2015-10-31T01:15:00"))
it returns
Friday, October 30 2015 at 02:15PM
when it should be returning
Friday, October 30 2015 at 10:15PM
as I'm Pacific time.
If I change
return os.date("%A, %B %d %Y at %I:%M%p", (utc_event_time-localoffset))
to
return os.date("%A, %B %d %Y at %I:%M%p", (utc_event_time+localoffset))
I get
Saturday, October 31 2015 at 04:15AM
Which again, is incorrect.
Where am I going wrong with this script? As a side note, the async is a client dependency, but it's essentially http.request.
Convert the Event time from Eastern to UTC, which I believe is done by adding the offset to the Event time.
Subtracting.
The offset shown in a timestamp is a signed number. It's already been "added" to UTC to generate the local time, so the inverse operation would be to subtract it. With -0400 being negative, you'd need to subtract negative 4 hours to convert back to UTC.

GAS function returns incorrect date - is it me or is it a defect?

Unless I use the .toLocaleDateString() method, the function below returns a date that is one day less than it should be. Am I doing something wrong or is this a defect?
function myDate() {
var sDate = '05/10/2012';
var parts = sDate.split('/');
var d = new Date( parts[2], parts[1]-1, parts[0]);
Logger.log(d);
Logger.log(d.toLocaleDateString());
};
The Logger returns:
Thu Oct 04 16:00:00 PDT 2012
05 October 2012 00:00:00 BST
I'm in the UK, hence the UK date format. I've checked that my project properties have the time zone set to "(GMT+00:00) London" so why does the Logger show the first date in PDT? Is that the reason for the wrong date? I've reproduced the problem in a stand-alone project. Here's a link to it.
I wanted to convert the string variable into a date object in order to do some date math so having to convert back to a string with .toLocaleDateString() method isn't helpful.
I've checked for consistence, thinking perhaps I could work around it, by testing with other dates. Bizarrely, if I change the value of sDate to anything between 01/01/2012 & 04/03/2012 it returns accurately. From 05/03/2012 onwards it drops a day. With 2013 dates, it returns correctly until 29/04/2013 when it starts dropping a day again. So it's not consistent. It seems similar to the problem reported here.
I found that dates read by the getValues() function on a range that were between the old DST rules and the new DST rules were decremented by 1 hour. So, the implicit time for the date "10/30/2012" is 00:00:00. But, when read in, it was decrementing by an hour, landing it in the previous day, i.e. 10/29/2012 23:00:00.
Any date between these two timeframes, not inclusive of the start day but inclusive of the end day, will exhibit this behavior currently, at least as read by the getValues() function:
Between the last Sunday in October and the first Sunday in November
Between the second Sunday in March and first Sunday in April.
I ended up writing code that would dynamically calculate these dates for the current year and if the date landed in the target range, I would simply increment it by an hour. This may be the the long way to fix it, but it works.
Here is my code:
/*
The old rules for DST stated that the time change occurred on the last Sunday in October,
which would be 10/28/2012. So, when you type in 10/29/2012, the timestamp associated with the date (00:00:00) is being decremented by an hour (23:00:00),
which drops it into the previous day. The new rules for DST states that DST ends on the 1st Sunday in November, which is 11/04/2012. Also, the DST rules
for springtime are also an impacted range of dates that exhibit this behavior, between the second sunday in March and the first sunday in April.
Note: Running this function from the script editor does not produce the strange DST behavior. It seems to be an issue with the getValues() function on a Range object.
*/
function fixDateDSTProblem(lstrDate){
var d = new Date(lstrDate);
//Example ranges affected
//10/29/2012 - 11/04/2012
//03/11/2013 - 04/07/2013
if(isNaN(d.getMonth())){
//return what was passed in if it's not a date or null.
return lstrDate;
}
else if(isAffectedDate(d)){
//increment by one hour
return new Date(d.getTime() + (60 * 60 * 1000));
}
else{
//date is not affected, simply return it as it was passed.
return lstrDate;
}
}
//Check to see if a date is within a beginning and end date
function dateWithin(beginDate,endDate,checkDate) {
var b,e,c;
b = Date.parse(beginDate);
e = Date.parse(endDate);
c = Date.parse(checkDate);
//slightly modified this for the date checking since beginning date is not inclusive, so needs to be > instead of >=
if((c <= e && c > b)) {
return true;
}
return false;
}
function isAffectedDate(targetDate){
var yearNum = targetDate.getFullYear();
//Get the last Sunday in October
var lastSunOctDateStr = getLastOccurrenceDate(0, 10, yearNum);
//Get the first Sunday in November
var firstSunNovDateStr = getOccurrenceDate(1, 0, 11, yearNum);
//Get the second Sunday in March
var secondSunMarDateStr = getOccurrenceDate(2, 0, 3, yearNum);
//Get the first Sunday in April
var firstSunAprDateStr = getOccurrenceDate(1, 0, 4, yearNum);
//if the date is between the last sunday in october and the first sunday in november
// or if the date is between the second sunday in march and the first sunday and april, fix it up!
if(dateWithin(lastSunOctDateStr, firstSunNovDateStr, targetDate) ||
dateWithin(secondSunMarDateStr, firstSunAprDateStr, targetDate)){
return true;
}
return false;
}
function getOccurrenceDate(numOccurrence, dayIndex, monthCalendar, yearNum){
//"Get date of first occurrence of Monday in June 2013"
//"Get date of the second occurrence of Sunday in April 2013"
//dayIndex: Sunday = 0, Saturday = 6
var monthIndex = monthCalendar - 1;
var numFirstXDay = null;
var firstDay = new Date(monthCalendar+"/01/"+yearNum);
var numDayOfWeek = firstDay.getDay();
if(numDayOfWeek == dayIndex){
numFirstXDay = 1;
}
else if(numDayOfWeek > dayIndex){
numFirstXDay = 1+(6-numDayOfWeek)+1+dayIndex+(7*(numOccurrence-1));
}
else if(numDayOfWeek < dayIndex){
numFirstXDay = 1+(dayIndex - numDayOfWeek)+(7*(numOccurrence-1));
}
return monthCalendar+"/"+numFirstXDay+"/"+yearNum;
}
function getLastOccurrenceDate(dayIndex, monthCalendar, yearNum){
//Example: "Get date of last occurrence of Monday in June 2013"
var monthIndex = monthCalendar - 1;
var numLastXDay = null;
//TODO: Handle Leap Year!
var monthMaxDaysArray = {
'1':'31',
'2':'28',
'3':'31',
'4':'30',
'5':'31',
'6':'30',
'7':'31',
'8':'31',
'9':'30',
'10':'31',
'11':'30',
'12':'31'}
var lastDay = new Date(monthCalendar + "/"+monthMaxDaysArray[monthCalendar]+"/" + yearNum);
var numDayOfWeek = lastDay.getDay();
if(numDayOfWeek == dayIndex){
numLastXDay = 31;
}
else if(numDayOfWeek > dayIndex){
numLastXDay = monthMaxDaysArray[monthCalendar] - (numDayOfWeek - dayIndex);
}
else if(numDayOfWeek < dayIndex){
numLastXDay = (monthMaxDaysArray[monthCalendar] - numDayOfWeek) - (6 - (dayIndex-1));
}
return monthCalendar + "/" + numLastXDay + "/" + yearNum;
}
The logger always logs dates in PDT. It's the same instance of time, just represented a different way. You are seeing that + differences in daylight savings time.
Even if Corey's answer doesn't need any confirmation (he knows what he is talking about ;) let me add some practical details ...
every javascript manipulation you do on date object (getDay, getTime, getFulYear...) will return correct values even if the logger value you see seems wrong so you don't need to convert to string and back to numbers if you need to manipulate dates
If these dates are shown in a spreadsheet then the spreadsheet locale settings will be used to show the desired values.
Sometimes you will see the values in other format in the logger... don't ask when or why but it happens to me sometimes (I'm in GMT+1 Belgium)
The date shift you notice in october and april are indeed happening when daylight savings starts and stops and this can become tricky when you need to define a date in a calendar event in one period from another (for example today I create an event in december there will be 1 hour difference) so you need to use the right GMT+0X00 value when you read a date object in a user interface using utilities.formatDate
If for some reason you show a list of dates starting before daylight savings switch day and ending after, and you use utilities.formatDate, it is better to user a variable to play with 'GMT+0X00' dynamically : I get it simply using something like this :
* EDIT* since a few weeks the syntax has changed and this string has to be formated differently, so I updated this code accordingly. (see issue 2204)
`var FUS1=new Date().toString().substr(25,6)+":00";// FUS1 gets the GMT+02:00 or GMT+01:00 string`
Hoping it's getting clear enough
Sorry to join the party a few months late...
The problem with these answers is that none of them actually make it clear that this is a BUG. Or, to be more precise, this is something that Google have decided is "correct" behaviour (see Issue 1271, for example, closed with no action), when it quite clearly is completely the wrong thing to do.
Consider this. I want to put someone's birthdate in a spreadsheet, and I have a large list of them. I then want to read out the value and put it in a form:
function getAge(ss, index) {
var ages = ss.getRangeByName("birthDates").getValues();
return ages[index];
}
...
app.createLabel(getAge(ss, index));
The form now contains the wrong birthdate for everyone born between April and October. Google has decided that they were actually born one day earlier. Or try to read out the ages, and put them in another spreadsheet, with no processing, where both spreadsheets have the same time zone setting. Same story, and it leaves me looking really stupid when people mail to tell me that I've got their birthdates wrong.
This is how it should be done: if someone manually specifies a date, for example "06/06/1997", then reads that date with getValue, they expect to get "06/06/1997" back, not the day before. They really don't expect you to try to second guess them: "Ok, this date happens to be during DST, so what they really expect to read back from getValue is something corrected to non-DST, so why don't we subtract an hour and give them the day before?"
It's crazy. If Excel did that, it would be a laughing stock. Fix it, please.
EDIT
Serge, that's very interesting, but your spreadsheet shows a work-around which extracts a TZ, and then displays according to that TZ. But that just avoids the issue that this is wrong to start with. Consider this. Spreadsheets almost invariably contain anniversaries of fixed dates - someone's birthday, the date of a battle, the time/date of an appointment, whatever. These are independent of TZ. If your birthday is 6th July 1960 in Belgium, then it's also 6th July if you happen to live in California. If you were born at 00:30AM, your passport still shows 6th July, even though that time was actually 5th July in CET and PDT. For an anniversary, or an appointment, no-one gives a damn about timezones. In a spreadsheet, only a tiny proportion of users care about TZ's. I can't immediately think of a single use-case where it actually matters.
Lotus 1-2-3 got this right. Excel got this right. A date is an integer serial number, with no time zone information. Copy a date from one spreadsheet to another, it's always right. Get a date from a spreadsheet using VB/whatever, put it in another spreadsheet, it's always right (I think). Much as I hate to say it, Excel defines spreadsheets, and they do it Good. Apart from VB.
In GAS, if I copy a date using getValues, it's wrong. Google have over-smarted this. Ok, there is a complex work-around that involves finding what TZ your spreadsheet was created in, assuming that the date you entered was actually an epoch date relative to UTC, and displaying it according to the spreadsheet's current TZ setting (at least, I think that's what you're doing). But so what? And, does it always work? What if you mail the spreadsheet to someone who lives in PDT? I'm sure you can get it to work, but that misses the point - this is just a work-around, which I think might be fragile (note that there are 3 TZ settings: the Google account setting, the sheet setting, and the script setting, and you have to take account of all of them - see ahab's post here). The fundamental issue is that Google spreadsheets store dates relative to a specific TZ (is the underlying format ms relative to Unix epoch??). This was just wrong, and is now unfixable, and is only one part of a large can of worms to do with date handling.
As a short-term fix, I can probably add 12 hours to all dates in a spreadsheet. As a longer-term fix, I should probably handle all dates as text strings and do it myself in JavaScript. I've already had to replace all elapsed times with "integral" number of milliseconds to handle the issues to do with lost milliseconds in GAS dates. Go on, convince me I'm wrong.
EDIT by Serge :
Hi, I took the liberty to answer in your edit for ease of reading (sorry about that).
I do understand your point of view but I don't share it.
The UI example you refer to needs indeed a workaround because this is pure javascript, not spreadsheet date ... That said, Excel spreadsheets and Google spreadsheets work the same way (next day is day+1, time = decimals and ref date 0 = 12/31/1899)) as long as you stay in the spreadsheet universe, the problem comes when you quit the spreadsheet and go to Javascript (ref date = 01/01/1970, count in milliSecs)...
If they had chosen not to care about TZ and keep dates 'static' across any time zone it would have had a lot of other issues : for example what if you want to setup an appointment on skype between me in Belgium and President Obama in Washington ? If we decide to have that conversation on monday at 8 AM will it be 8 AM in Belgium or in Washington ?
With the Google solution he will just have to wake up a bit early but we will both be there since the date and time would show the same 'moment', with the way you suggest there won't be any chance we talk to each other (how sad that would be^^) .
There are a lot more situation where it is obviously a better choice : communication with Calendar service is also a good example.
The static excel solution works nicely because such a document isn't shared the same way and doesn't convert dates to Javascript date Objects. An Excel SS is related to the computer's user, a Google SS keeps this relation to the user's computer using the Time Zone setting because it is (by nature) not related to user's computer.
I have little hope to convince you (;-) but I hope this will at least make things a bit clearer... (and anyway I'm not a Google engineer and have no way to influence them in any way ^^).
one more EDIT...
Here is a small test sheet with TZ settings set to GMT-8 that gets the value of the other test sheet (set to GMT+2 Belgian winter time) and shows it the right way by using this simple script :
function timeCorrection() {
var thisSheet = SpreadsheetApp.getActiveSheet();
var otherSS = SpreadsheetApp.openById('0AnqSFd3iikE3dENrc2h1M0ktQTlSNWpNUi1TS0lrNlE');
var otherSheet = otherSS.getSheetByName('Sheet1');
var otherValue = otherSheet.getRange(1,1).getValue();
var tz = otherSS.getSpreadsheetTimeZone();
var thisSheetValue = new Date(Utilities.formatDate(otherValue,tz,'MM/dd/yyyy HH:mm:ss'));
thisSheet.getRange(1,1).setValue(thisSheetValue);
}
As simple as that ;-) , settings of the 'foreign sheet' are set to the same value as its script settings which is default for a newly created sheet created in Vancouver.
This is not a bug...
May I offer another solution to the problem that is less programmatic? I isolated this issue and spend a day trying to figure out why my script was pulling dates with a previous day and 23:00PM.
Then, I realized that Spreadsheet is not a comma separated database but has its auto-formatting. So, the problem is solved when in Spreadsheet I selected my column containing dates and from menu chose Format>Numbers>Plain Text. Now my script runs perfect without tons of way around. Applying this to an entire column affects even a newly added cells. So its a sweet solution.
Since this is stackoverflow, here is the java solution (I check it works):
sheet.getRange(1,n).setNumberFormat('#STRING#');
I took it from christian.simms, from here:
Format a Google Sheets cell in plaintext via Apps Script
The main problem is incorrect time zone for a date object.
So I not found way to get a string from a cell if it has date type. The cell will return representation based on the time zone but it is not the same as on local computer, so you can get date ± one day.
You can get the time zone for the current account:
var userTimeZone = CalendarApp.getDefaultCalendar().getTimeZone();
Warning! This is not time zone of local computer, so this is another problem.
So you can get correct string of the date:
var date1 = SpreadsheetApp.getActiveSheet().getRange(1, 1).getValue();
var str = date1.toLocaleString("en-US", {timeZone: userTimeZone });

Resources