DateTime, the Epoch and DocumentDb - c#

So I read this very interesting blog on working with datetime in Azure DocumentDb. The problem being that, right now, Azure DocumentDb does not support range search on datetime fields. The reason for that is that DocumentDb is based on json and that has no datetime type, therefore one usually puts it in a string of xml datetime format.
(obviously Mongo does not have that issue, it's bson format adds the datetime type (among others))
Anyway, the article describes storing the datetime in json in an epoch (unix) time, essentially storing the datetime as an amount of seconds since 01-01-1970. One problem of epoch is that it does not take leap seconds into account, but I can live with that for now.
My question is that I would also like to store birth dates in such a format. Now I could just take 01-01-1900 as a start date and store the amount of days since that date in an int. While I am pretty sure this would work well, it feels like epoch is a well established concept, but the one for birthdays feels like I am building my own conventions, which is something I generally like to avoid.
Is there any established standard for standardizing date storage as a number? Which date should be the baseline date?

First of all, an update: DocumentDB now supports range indexes on both strings and numbers. You have to set up the indexes correctly for it to work.
Now, to give you a recommendation. I've been successful storing ISO-8601 timestamps as strings. This is the default format used by the DocumentDB SDK for handling DateTime so it's less work than converting to an integer.
ISO-8601 date/time strings have several properties that match your needs.
The alpha-numeric sort order is chronological so it works perfectly as expected with query clauses using >, <, >=, <=, and BETWEEN assuming you have a range index of appropriate precision (-1 for full precision);
They are human readable so if you are browsing a table, the data makes sense;
This format allows for the specification of lower granularity date/time. For instance, you should say "2015-03" to mean the month of march, or "2015-03-24" to mean March 24, 2015. You can then issue a query with this filter "startedOn >= 2015-03-24 AND startedOn < 2015-03-25" to find everything that started on March 24, 2015. This works even when startedOn is stored as a full ISO-8601 string like "2015-03-24T12:34:56.789Z" due to the nature of string comparison.
I've written about this approach here.

The answer by Teo is correct, except that I suspect in terms of being "well established", the billions of Microsoft Excel, LibreOffice, and Lotus 1-2-3 spreadsheets with their own epoch may far outnumber Unix Time usage. Or the billion of Apple Cocoa devices and computers with their own epoch.
Be aware that a couple dozen different epochs have been used by various computer environments. Unix time is far from being alone or even dominant.
Also be aware that there is no such thing as Unix time exactly. Variations include using whole seconds, milliseconds, microseconds, or nanoseconds.
When possible, use a date-time savvy data type. Be sure to study the doc and experiment to understand clearly it's behavior.
Where not possible to use a data type, fallback to using a string in the various ISO 8601 formats. Some of those standard formats are alphabetically chronological in sorting, especially for date-only values: YYYY-MM-DD.
Leap seconds are ignored in every date-time tracking system I know of. Their purpose is to make our hourly clock jive with calendar, so for business purposes the Leap Second is in a sense meant to be ignored.
Date-time work is surprisingly tricky and slippery business. Search StackOverflow to discover the many issues. Try to avoid rolling your own solutions. For C# in particular, look at the Noda Time library.

In my experience i haven't encountered a more 'established' standard than the UNIX epoch. This being said, some architectural/technological aspects of time storage have been discussed before:
Timestamps and time zone conversions in Java and MySQL
I would ask why risk using your own convention? It's a risk because: what if some time you will want to add hours to your day count, maybe to be able to order people based on when exactly during the day they were born. The question can be extended to: what if at some point you want to measure more generic or more fine-grained moments; you would have to translate your entire feature, possibly throughout many layers of your application, to a more generic mechanism/convention. Another (similar) question would be: will you always measure once-in-a-lifetime events for the people in your database or will they be able to create new, unlimited events? As the number of events increases the risk of collision increases too and a day count would not be as suitable as a timestamp measured in seconds or milliseconds.
UNIX time is basically ubiquitous, you have special methods for getting it in most programming languages. The time-keeping architecture i will always support & implement in my projects is this:
http://www.currentmillis.com/tutorials/system-currentTimeMillis.html
As also stated in my answer to the question linked above, the advantages of storing time as milliseconds since the UNIX epoch are:
architecture clarity: server side works with UTC, client side shows
the time through its local timezone
database simplicity: you store a
number (milliseconds) rather than complex data structures like
DateTimes
programming efficiency: in most programming languages you
have date/time objects capable of taking milliseconds since Epoch
when constructed (which allows for automatic conversion
to client-side timezone)
Because you mentioned C#, DateTime.MinValue comes to mind. This would basically be the year 0 (midnight, 1st of January).
Also, this would be some code which would allow you to get the millis since your chosen reference date (whatever it is) but note that 1900 is still different than .NET's 'epoch' (DateTime.MinValue)
// Unix Epoch
(DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalMilliseconds
// NTP Epoch
(DateTime.UtcNow - new DateTime (1900, 1, 1)).TotalMilliseconds

Related

C# DateTime Format YYMMDDhhmmsstnnp

I'm currently using a third party DLL to run some of my programs.
It was working fine until recently I decided to move it to a new server running OS Windows Server 2016.
The library suddenly pops an error saying:
System.FormatException: Incorrect format. 'YYMMDDhhmmsstnnp'
I looked here https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings but couldn't see anything for t, nn and p.
Does anyone recognize the format above and knows what actually is t nn and p?
And how do I actually resolve the issue?
Thank you
Okay, after a little detective work (well, a search) I believe you're probably using the SMPPClient library, and that the error comes from this line. It's not trying to use that as a format string - it's only reporting it (unhelpfully, IMO) as the expected format of the string.
It's actually checking it using this regex:
"^[0-9][0-9][0-1][0-9][0-3][0-9][0-2][0-9][0-5][0-9][0-5][0-9][0-9][0-4][0-9][\\+\\-R]$"
The SMPP v5 specification explains the formatting:
‘YY’ last two digits of the year (00-99)
‘MM’ month (01-12)
‘DD’ day (01-31)
‘hh’ hour (00-23)
‘mm’ minute (00-59)
‘ss’ second (00-59)
‘t’ tenths of second (0-9)
‘nn’ Time difference in quarter hours between local time (as expressed in the first 13 octets) and UTC (Universal Time Constant) time (00-48).
‘p’:
“+” Local time is in quarter hours advanced in
relation to UTC time.
“-” Local time is in quarter hours retarded in
relation to UTC time.
This isn't something I'd expect a regular format string in .NET to handle.
I would suggest that your next steps should be:
Find out what value it was trying to parse (that could be tricky, I understand)
Work out where that value comes from (is it generated elsewhere in the code, possibly in your code, or is it data originating outside your system?)
Write a small program to just perform that regex on both the working machine and the problematic machine to work out whether the problem is that the regex behaviour has changed, or the data being parsed has changed
My guess is that some code somewhere is using regular DateTime formatting to create part of this string, and then tweaking it for the last part... and that on your new system, there are some locale changes that affect things. For example, even if you format with an explicit format, that will still use the calendar system of whatever culture it's using - if you're formatting to a non-Gregorian calendar accidentally, that could definitely affect things. (The common fix there is to explicitly use CultureInfo.InvariantCulture when formatting a machine-readable string.)

IANA/Olson timezone support in C#

C# supports different timezone id's across the globe. Please find list of time zones that are being supported by C# in below link:
https://msdn.microsoft.com/en-us/library/gg154758.aspx
The timezone id's are used in C# library functions to convert times across the timezones.
[e.g. TimeZoneInfo.ConvertTimeBySystemTimeZoneId("Hawaiian Standard Time")]
Similarly I want support for AMERICA/MIQUELON, which is not present in the msdn list provided in above link.
Can somebody please provide workaround for this specific timezone?
Time zone identifiers like "America/Miquelon" and the others you listed (before editing your question) are from the IANA time zone database. You can read more in the timezone tag wiki and on Wikipedia.
Note that they are usually presented in mixed case form, rather than in all capital letters.
The easiest and best way to work with these in .NET is via the Noda Time library.
For example:
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/Miquelon"];
Instant now = SystemClock.Instance.Now;
ZonedDateTime converted = now.InZone(tz);

Globally convert UTC DateTimes to user specified local DateTimes

I am storing all the DateTime fields as UTC time. When a user requests a web page, I would like to take his preferred local timezone (and not the local timezone of the server machine) and automatically display all the DateTime fields in all the web forms as local dates.
Of course, I could apply the conversion on every DateTime.ToString() call in every form or implement some helper utility but it is a time consuming task, and also there are some 3rd party components which are tricky to configure with custom DateTime display templates.
Essentially, I would like to make the DateTime class to behave as follows:
from this moment on for this web request,
whenever some code calls DateTime.ToString(), convert it to the local time
using the timezone offset given at the very beginning of the web request,
but if possible, please keep .NET core library DateTime.ToString() calls intact
(I don't want to mess up event logging timestamps etc.)
Is there any way to do it?
BTW, I am using ASP.NET MVC 4, if it matters.
You can't do directly what you asked for, but I will suggest some alternatives. As Nicholas pointed out, there is nothing in HTTP that would give you the time zone directly.
Option 1
First, decide which type of time zone data you want to work with. There are two different types available, either the Microsoft time zones that you can access with the TimeZoneInfo class, or the IANA/Olson time zones that the rest of the world uses. Read here for more info. My recommendation would be the latter, using the implementation provided by NodaTime.
Then determine which time zone you want to convert to. You should allow your user a setting somewhere to pick their time zone.
You might show a drop-down list to pick one of several time zones, or you might do something more useful, like display a map of the world that they can click to select their time zone. There are several libraries that can do this in Javascript, but my favorite is this one.
You might want to guess a default time zone to use, so you can be as close to accurate as possible before they pick from the list (or map). There is a great library for this called jsTimeZoneDetect. It will interrogate the browser's clock and make a best guess assumption of what time zone it might be. It is fairly good, but it is still just a guess. Don't use it blindly - but do use it to determine a starting point. Update You can now also do this with moment.tz.guess(), in the moment-timezone component of moment.js.
Now that you know the time zone of the user, you can use that value to convert your UTC DateTime values to that local time zone. Unfortunately, there is nothing you can set on the thread that will do that. When you change the system time zone, it is global for all processes and threads. So you have no choice but to pass the time zone to each and every place you are sending it back. (I believe this was your main question.) See this almost duplicate here.
Before you convert it to a string, you will need to also know the user's locale (which you can get from the Request.UserLanguages value). You can assign it to the current thread, or you can pass it as a parameter to the DateTime.ToString() method. This doesn't do any time zone conversion - it just makes sure that the numbers are in the correct position, using the correct separators, and the appropriate language for names of weekdays or months.
Option 2
Don't convert it to local time on the server at all.
Since you said you are working with UTC values, make sure their .Kind property is Utc. You should probably do this when you load from your database, but if you have to you can do it manually:
myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);
Send it back to the browser as pure UTC, in an invariant format like ISO8601. In other words:
myDateTime.ToString("o"); // example: "2013-05-02T21:01:26.0828604Z"
Use some JavaScript on the browser to parse it as UTC. It will automatically pick up the local time settings of the browser. One way is to use the built-in Date object in JavaScript, like this:
var dt = new Date('2013-05-02T21:01:26.0828604Z');
However, this will only work in newer browsers that support the ISO-8601 format. Instead, I recommend using the moment.js library. It is consistent across browsers, and it has better support for ISO dates, and localization. Plus you get a lot of other useful parsing and formatting functions.
// pass the value from your server
var m = moment('2013-05-02T21:01:26.0828604Z');
// use one of the formats supported by moment.js
// this is locale-specific "long date time" format.
var s = m.format('LLLL');
The advantage of Option 1 is that you can work with times in any time zone. If you can ask the user for their timezone from a dropdown list, then you need not use any Javascript.
The advantage of Option 2 is that you get the browser to do some of the work for you. This is the best way to go if you're sending out raw data, such as making AJAX calls to a WebAPI. However, JavaScript is only aware of UTC and the browser's local time zone. So it doesn't work so well if you need to convert to other zones.
You should also be aware that if you choose Option #2, you may be affected by a flaw in the design of ECMAScript 5.1. This comes into play if you are working with dates that are covered by a different set of daylight saving time rules than are currently in effect. You can read more in this question, and on my blog.
It would be so much easier if we had some time zone information in the HTTP headers, but unfortunately we don't. These are a lot of hoops to jump through, but it's the best way to have both flexibility and accuracy.
The short answer is that you can't. HTTP doesn't require (or even provide a standard way) for the user agent (browser) to provide local time or timezone information in the HTTP request.
You either need to
ask the user for their preferred time zone, or
have client-side javascript report it to you somehow (cookie? ajax? other?)
Bear in mind that a client-side javascript solution isn't perfect, either. Javascript disabled (or non-existent, for some browsers). Javascript might not have access to timezone information. Etc.

Is there a generic representation of date using Epoch? Ticks vs milliseconds since Epoch

I am building an API that needs a date and I want to represent it using the Epoch.
Since I am developing in C# in .NET the ticks is an easy representation (100 nanosecods).
However, I need also to cater to implementors of the API in other programming languages.
Is the concept of Ticks used other than in C#? Should I go back to milliseconds since Epoch so the API is not designed too much with a .net flavor?
I know how to do the conversions, but I am looking for what makes more sense. My goal is to make the representation of dates easy for any programmer in all languages that may implement this API.
Thanks,
Whether you choose to use XML in your API or not, the standard defined in the XML Schema Part 2: Datatypes Second Edition is a pretty safe bet. See section 3.2.7, advising a specific version of one of the many ISO-8601 formats.

How to convert UTC time to Time in any other time zone in C#

I am working in C#.net - .Net fx is 2.0 which doesnot support converting between different time zones. I have wrote a scheduler based on UTC but it is giving errors of 1 hour in the DTS periods for London. I need some solution so that I can gat the correct time in any timezone relative to UTC with correct DST adjustments.
Is changing to .NET 3.5 absolutely out of the question? It would make your life much, much easier. Otherwise, you're stuck with the plain TimeZone and DaylightSavings classes, as well as having to fetch the known timezones using P/Invoke.
William Stacey has a blog post with some code to do this - but I haven't tried it, so can't vouch for its accuracy. (In my experience he's usually pretty good though :) There are no doubt similar bits of code around if that one doesn't help you.
I believe that the API he's using doesn't have access to historical data, btw. In other words, it will assume that DST always kicks in on the first Sunday of October (or whatever the rule is) rather than knowing that the rule has changed over time. TimeZoneInfo in .NET 3.5 supports historical data where the OS does.

Categories

Resources