NSDateFormatter Corruption - nsstring

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
NSTimeZone *gmt = [NSTimeZone systemTimeZone];
[dateFormatter setTimeZone:gmt];
NSString* fileTime = [infoArray objectAtIndex:5];
NSDate* sessionStartDate = [dateFormatter dateFromString:fileTime];
NSLog(#"%#", [infoArray objectAtIndex:5]);
NSLog(#"%#", sessionStartDate);
The two NSLogs:
2013-07-17 01:28:50
2013-07-17 05:28:50 +0000
Two should be the same, but not. The hour shows up differently. I did try 'hh' instead of uppercase, but same issue.

Your system timezone is not GMT, while NSDateFormatter parses the date string w.r.t GMT (you have time zone missing in date string, so it assumes time zone to be GMT).
So what you get is the GMT time from time string converted to your local time.
Use
NSTimeZone *gmt = [NSTimeZone timeZoneWithName:#"GMT"];
and you will get both the date same.

Related

Weird time offset dealing with date/time and timezone

I have been trying to code some functions to create google calendars and google calendar events based on information from multiple cells on a google spreadsheet.
First issues posted here with the date part has already been addressed.
Now I´m haing issues with the Time part.
The following code:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Passeios");
var timeStart = ss.getRange(6,4).getValue();
var timeEnd = ss.getRange(6,5).getValue();
var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
Logger.log("timeStart: " + timeStart );
Logger.log("timeEnd: " + timeEnd);
var dateStart = ss.getRange(6,8).getValue();
var dateStartObj = new Date(Utilities.formatDate(dateStart, 'ssTZ' , 'MMMM dd, yyyy HH:mm:ss Z'));
var timeStartObj= new Date(Utilities.formatDate(timeStart, 'ssTZ' , 'MMMM dd, yyyy HH:mm:ss Z'));
var justTimeStart = Utilities.formatDate(timeStart, ssTZ, 'HH:mm');
Logger.log(" Time Start Object: " + timeStartObj);
Logger.log("Time Start Object Hours: " + timeStartObj.getHours());
Logger.log("Time Start Object Minutes: " + timeStartObj.getMinutes());
Logger.log("Start Time HH:mm: " + justTimeStart)
var hourStart = Utilities.formatDate(timeStart, ssTZ, 'HH');
var minutesStart = Utilities.formatDate(timeStart, ssTZ, 'mm');
var hourEnd = Utilities.formatDate(timeEnd, ssTZ, 'HH');
var minutesEnd = Utilities.formatDate(timeEnd, ssTZ, 'mm');
Logger.log(" TimeZone :" + ssTZ);
Logger.log(hourStart);
Logger.log(minutesStart);
Logger.log(hourEnd);
Logger.log(minutesEnd);
Produces the following log
timeStart: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
timeEnd: Sat Dec 30 1899 07:36:28 GMT-0300 (BRT)
Time Start Object: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
Time Start Object Hours: 7
Time Start Object Minutes: 6
Start Time HH:mm: 07:00
TimeZone :America/Sao_Paulo
07
00
07
30
The Spreadsheet cell is formatted as HH:mm and it shows
07:00 for start time
07:30 for end time
As you can see there is some 6 minutes and 28 seconds offset that I am not sure where is coming from when logging the cell value or when constructing a Date() object with the cell value.
Formating the cell to just Hours or just Minutes or HH:mm does not carry that offset.
EDIT.
I noticed that the Date() constructor had the ssTZ variable between single quote marks so it is probably discarded as it should not be recognized as a valid Timezone.
Not sure what it uses instead but the difference between the actual spreadsheet time zone and the misquoted one, seems to be 28 seconds that I also do not understand where they come from.
The 6 minutes offset is still there as you can check on the following code and log print.
var timeStart = ss.getRange(6,4).getValue();
var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var timeStartObj1= new Date(Utilities.formatDate(timeStart, 'ssTZ' , 'MMMM dd, yyyy HH:mm:ss Z'));
var timeStartObj2= new Date(Utilities.formatDate(timeStart, ssTZ , 'MMMM dd, yyyy HH:mm:ss Z'));
var justTimeStart = Utilities.formatDate(timeStart, ssTZ, 'HH:mm');
Logger.log("timeStart: " + timeStart );
Logger.log(" Time Start Object1: " + timeStartObj1);
Logger.log(" Time Start Object2: " + timeStartObj2);
Logger.log("justTimeStart: " + justTimeStart)
timeStart: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
Time Start Object1: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
Time Start Object2: Sat Dec 30 1899 07:06:00 GMT-0300 (BRT)
justTimeStart: 07:00
EDIT 2
It has something to do with timezone and probably some adjustment due to the Date beign interpreted as 120 years ago in 1899.
When using the following constructor without the Z at the string specifying the format:
var timeStartObj3= new Date(Utilities.formatDate(timeStart, ssTZ , 'MMMM dd, yyyy HH:mm:ss'));
Logger.log(" Time Start Object3: " + timeStartObj3);
The log result is:
Time Start Object3: Sat Dec 30 1899 07:00:00 GMT-0300 (BRT)
EDIT 3.
Getting weirder and weirder...
If I use text concatenation on the Logger.log call I get a different String that if I call the log with just the var name:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Passeios");
var timeStart = ss.getRange(6,4).getValue();
Logger.log("timeStart: " + timeStart);
Logger.log(timeStart);
timeStart: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
Sat Dec 30 07:00:00 GMT-03:06 1899
I do understand it is in fact the same Time represented differently (I asume the 28 seconds are there even when not shown).
My guess is there's different behaviour from the text parsing method whether concatenation is used or not (which is at least confusing).
I still do not know where those 06 minutes and 28 seconds come from or how to ensure consistency when using Time and date coming from cell values with just date or just time and having to mix them.
This is really confusing...
The 6 minutes and 28 seconds come from the Local Mean Time (LMT) offset between São Paulo and GMT. You can see it in the TZDB sources:
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Sao_Paulo -3:06:28 - LMT 1914
-3:00 Brazil -03/-02 1963 Oct 23 0:00
-3:00 1:00 -02 1964
-3:00 Brazil -03/-02
The LMT entry is in the first row. The last column (1914) is the "Until" date - meaning that in the TZDB, LMT is in use until 1914. After that, the next rule in the zone entry applies (-3:00).
LMT is calculated based on the longitude and latitude of the reference location. It has no bearing on timekeeping that may have been in use in the region at that time. In many cases with old dates, there's no historical information available to know how exactly time was kept that long ago.
In other words, your example date from 1899 is from a period before known timekeeping practices in Brazil, and thus local mean time is applied instead.
Use a more modern date and you should get results that make more sense to you by today's standards.
Google sheets stores a Date or time cell value as a number corresponding to the number of full days (or fractions) starting 12/30/1899 0:00:00 as explained here.
When dealing with a cell that only contains a Time value, the getValues() function will produce a Date object with the date part set to 12/30/1899 but this will have a corresponding timezone offset which in time creates that odd offset as explained by #Matt Johnson on previous answer
The big problem is that this offset will not be consistent for diferent timezones as that date will produce different offsets for different locations/timezones and different years, so you will need to address a whole bunch of possible situations.
When trying to create Date() objects, this produces different results as it seems sometimes that offset is passed as a timezone offset and other times it is part of the actual time value depending on the constructor and format the text gets parsed to, creating a lot of confusion, as you can see from this code:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Passeios");
var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var timeStart = ss.getRange(6,4).getValue();
var date1 = new Date(timeStart);
var date2 = new Date(Utilities.formatDate(timeStart, ssTZ , 'MMMM dd, yyyy HH:mm:ss Z'));
var date3 = new Date(Utilities.formatDate(timeStart, ssTZ , 'MMMM dd, yyyy HH:mm:ss'));
var date4 = new Date(Utilities.formatDate(timeStart, ssTZ , "yyyy-MM-dd'T'HH:mm:ss'Z'"));
Logger.log("date1: " + date1);
Logger.log("date2: " + date2);
Logger.log("date3: " + date3);
Logger.log("date4: " + date4);
Producing this log:
date1: Sat Dec 30 1899 07:06:28 GMT-0300 (BRT)
date2: Sat Dec 30 1899 07:06:00 GMT-0300 (BRT)
date3: Sat Dec 30 1899 07:00:00 GMT-0300 (BRT)
date4: Sat Dec 30 1899 04:00:00 GMT-0300 (BRT)
Sometimes the timezone offset is ignored alltogether, other times, only the seconds part is ignored and also it might be interpreted as a completely different timezone by hours. (That string format was taken from the formatDate() class documentation example)
As #TheMaster suggested, this might be addressed at the spreadsheet creating auxiliary cells/column on the sheet to add a more consistent date part but this might not be practical in cases where this information is dynamically processed (in my case a combination of multiple QUERY results across multiple answers from multiple associated forms).
Another approach also suggested by #TheMaster might be to use getDisplayValues() and parse the text but this might create all sort of trouble if the display format is ever changed in the sheet.
There doesn't seem to be a definitive answer
I think the least messy approach to this problem will be to use numeric variables in the code and parse numeric values just for the Hours and minutes using Utilities.formatDate() with the format property set just to 'HH' and 'mm' respectively.
var hours = Utilities.formatDate(timeStart, ssTZ, 'HH');
var minutes = Utilities.formatDate(timeStart, ssTZ, 'mm');
Logger.log("Hours: "+ hours);
Logger.log("Minutes: "+ minutes);
Gives the following result:
Hours: 07
Minutes: 00
This seems to be consistent and it disregards the timezone associated offsets and will produce a simple number for the hour and a simple number for the minutes corresponding to de displayed values at the sheet, which can then be used consistently to create Date() objects.
Note that the cell on the spreadsheet still needs to be formatted as Date/time for this to work but different from parsing text from a getDisplayValues() result, any date/time format will still work the same.
I'm not interested in the seconds or milliseconds but I suspect those could be addressed the same way.
Hopefully this helps someone else along the way.

moment-timezone.js get utc offset for a specific date with timezone

I have users entering a date and a time zone (e.g. "America/Los Angeles") for that date and I'd like to convert that to UTC but to do that I need the utc offset for the time on that date.
I can easily convert a date to the offset for the time zone if I already know the UTC date but I need the other way around...
The utc offset can change depending on the date due to daylight saving so I need a way to enter a date and a timezone and get back the offset from UTC using that.
Knowing the most recent switch from PST to PDT On march 11 at 2AM I tried using
var tzOffset = moment.tz("3/11/2018 3:00 AM", "America/Los_Angeles").utcOffset();
document.write('utc offset is : ' + tzOffset + '<br/>') ;
but that gives 480 when the correct answer is 420
I can get the correct answer 420 if I use parseZone like so:
var tzOffset2 = moment.parseZone("3/11/2018 3:00 AM -07:00").utcOffset();
document.write('utc offset2 is : ' + tzOffset2 + '<br/>') ;
but that means I need to already know the -7 offset that I'm trying to find...
So how do I find the utcOffset for a specific date/time like "3/11/2018 3:00 AM" and timezone like "America/Los_Angeles"? Thanks
Your input is not in a ISO 8601 or RFC 2822 format recognized by moment(String), so you have to specify the format as second parameter using moment(String, String) (please note that, as docs states: The moment.tz constructor takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier.)
Your code could be like the following:
var tzOffset = moment.tz("3/11/2018 3:00 AM", "D/M/YYYY h:mm A", "America/Los_Angeles").utcOffset();
document.write('utc offset is : ' + tzOffset + '<br/>') ;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.14/moment-timezone-with-data-2012-2022.min.js"></script>

How to convert the month name in english text in datetime to arabic text using C#?

I have a date which is displayed on 12 July 2013. I am using the format "dd MMMM yyyy". I want to display the month text i.e. July in Arabic text. Is there anyway?
Am getting يوليه as result instead يوليو, My client, saying: the month of July is “يوليو” in Arabic, while on the website it is showing as “يوليه”. Which is wrong,
can anyone help me on this?
Please find the code below.
What I have tried:
CultureInfo uiCulture1 = CultureInfo.CurrentUICulture; //'ar-AE'
DateTime dDateTime2 = DateTime.Parse(dt.ToString(), uiCulture1, System.Globalization.DateTimeStyles.AssumeLocal);
lblDate.Value = dt.ToString("dd MMMM yyyy");
try this
var dateTime = DateTime.Now;
var month = DateTime.Now.ToString("MMMM", new CultureInfo("ar-AE"));
Console.WriteLine(month);
result أكتوبر
I think the issue is the
dt.ToString()
in the Date.Parse. The dDateTime2 is getting set to 07 December instead of 12 July because I think the Culture in question is defaulting to dd-mm-yyyy for date format.
var dt = new DateTime(2013, 07, 12);
Console.WriteLine(dt.ToString("dd MMMM yyyy")); //12 July 2013
CultureInfo uiCulture1 = new CultureInfo("ar-AE"); //'ar-AE'
DateTime dDateTime2 = DateTime.Parse(dt.ToString(), uiCulture1, System.Globalization.DateTimeStyles.AssumeLocal);
Console.WriteLine(dDateTime2.ToString("dd MMMM yyyy")); // 07 December 2013
Console.WriteLine(dt.ToString("dd MMMM yyyy", uiCulture1)); //12 يوليو 2013
provide the culture info in dateTime.toString()
var dateTime = DateTime.Now;
var uiCulture = new CultureInfo("ar-AE");
Console.WriteLine(dateTime.ToString("dd MMM yyyy",uiCulture));

Behind The Scenes: Core Data dates stored with 31 year offset?

I know, "no user-serviceable parts inside" ... but I'm curious:
In a Core Data sqlite3 DB, it seems I can get at the date within a ZDATE like so:
sqlite> select datetime(ZDATE,'unixepoch','31 years','localtime') from ZMYCLASS;
2003-12-11 19:00:00
2009-12-31 19:00:00
2009-01-24 19:00:00
2011-01-01 19:00:00
2009-10-03 20:00:00
...
Unix Epoch I get, but why 31 years?
Core Data stores dates relative to reference date, which is Jan 1st, 2001 (31 years after EPOCH as pointed out in the comments)
Here's some code to decode the dates from the table, in case it is useful to you.
NSNumber *time = [NSNumber numberWithDouble:(d - 3600)];
NSTimeInterval interval = [time doubleValue];
NSDate *online = [NSDate dateWithTimeIntervalSinceReferenceDate:interval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM/dd/yyyy HH:mm:ss.SSS"];
NSLog(#"result: %#", [dateFormatter stringFromDate:online]);
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html
Take a look at + dateWithTimeIntervalSinceReferenceDate:

Don't know what format date is to be able to parse it '[1252457867]'

I have a date/time field from a shopping cart API feed, but I don't know what format it is in and I don't have access to the database.
What could [1252457867] be for a date?
These dates are all within the last couple weeks
Any ideas?
Clearly a unix timestamp.
1252457867 = 09 Sep 2009 - 02:57:47
This sounds like seconds since the Unix Epoch (January 1, 1970).
That looks like seconds elapsed since Jan. 1st, 1970 12:00AM.
Use this function to get the date:
var baseDate = new DateTime(1970, 1, 1, 0, 0, 0);
var transactionDate = baseDate.AddSeconds(1252457867);
This will output {9/9/2009 12:57:47 AM} PST
**EDIT: **
If you need UTC:
var utcDate = baseDate.AddSeconds(1252457867).ToUniversalTime();
This outputs {9/9/2009 7:57:47 AM}
--Adam

Resources