Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
C# Extension Methods to handle ISO-8601 with the same exact ISOFormat used in Javascript
public static class ISOFormatExtensions
{
const string ISOFORMAT = "yyyy-MM-dd\\THH:mm:ss.fffK"; //ISO-8601 used by Javascript (ALWAYS UTC)
public static string toISOString(this DateTime d, bool useLocal = false) {
if (!useLocal && d.Kind == DateTimeKind.Local) {
//If d is LT or you don't want LocalTime -> convert to UTC and always add K format always add 'Z' postfix
return d.ToUniversalTime().ToString(ISOFORMAT);
} else { //If d is already UTC K format add 'Z' postfix, if d is LT K format add +/-TIMEOFFSET
return d.ToString(ISOFORMAT);
}
}
public static DateTime fromISOString(this DateTime d, string s, bool useLocal = false) {
//Return a new DateTime parsed used ISOFORMAT - YOU MUST PASS A STRING ENDING WITH 'Z' OR +/-TIMEOFFSET
var l = DateTime.ParseExact(s, ISOFORMAT, System.Globalization.CultureInfo.InvariantCulture);
return useLocal ? l : l.ToUniversalTime(); //If you don't set useLocal returned date is always Kind=UTC
}
public static DateTime fromISOString(this DateTime d, string date, string time, bool useLocal = false) {
//Return a new DateTime buiding an ISOFROMAT string from date, time params expressed in UTC (by default) or in LT if you set useLocal=true
var sb = new System.Text.StringBuilder(30);
if (!string.IsNullOrEmpty(date)) { sb.Append(date); sb.Replace('-', '/'); }
if (!string.IsNullOrEmpty(time)) { sb.Append(' '); sb.Append(time); }
var s = sb.ToString();
if (!useLocal) { //Always return DateTime Kind=UTC, if you don't pass +/-TIMEOFFSET or 'Z' postfix I'll add it by default (as needed for UTC)
if (!(s.Contains('Z') || s.Contains('+') || s.Contains('-'))) s += "Z";
return d = DateTime.Parse(s, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal | System.Globalization.DateTimeStyles.AssumeUniversal);
} else { //Return DateTime Kind=Local and do necessary conversion to LT if you pass time with +/-TIMEOFFSET or referred as UTC with 'Z' postfix
return d = DateTime.Parse(s, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeLocal);
}
}
}
@dmorosinotto

This comment has been minimized.

Copy link
Owner Author

@dmorosinotto dmorosinotto commented Apr 24, 2018

//SAMPLE USING Extension Methods IN C#
var u = DateTime.UtcNow;
var n = DateTime.Now;
Console.WriteLine("NOW {0} n.KIND={1} -> {2} in LT {3}",n,n.Kind,n.toISOString(),n.toISOString(true));
Console.WriteLine("NOWUTC {0} u.KIND={1} -> {2} in LT {3}",u,u.Kind,u.toISOString(),u.toISOString(true));
var ok = new DateTime().fromISOString(n.toISOString(),true);
var okZ = new DateTime().fromISOString(u.toISOString());
Console.WriteLine("ASSERT NOW {0} {1}",(ok-n).TotalMilliseconds, ok.Kind);
Console.WriteLine("ASSERT NOWUTC {0} {1}",(okZ-u).TotalMilliseconds, okZ.Kind);
Console.WriteLine("-------------------------------------------------");
var z = new DateTime().fromISOString("2018-04-26","14:46:23.456Z"); //14.46Z
Console.WriteLine("Z UTC {0} KIND={1} ISO={2}",z,z.Kind,z.toISOString());  
var y = new DateTime().fromISOString("2018/04/26","14:46:23.456");  //14.46Z
Console.WriteLine("Y LT+TOFF {0} KIND={1} ISO={2}",y,y.Kind,y.toISOString());
var x = new DateTime().fromISOString("2018/04/26","14:46:23.456+02:00"); //12.46Z
Console.WriteLine("X LT->UTC {0} KIND={1} ISO={2}",x,x.Kind,x.toISOString());
Console.WriteLine("-------------------------------------------------");
var l = new DateTime().fromISOString("2018/04/26","14:46:23.456",true);  //12.46Z <- LT=14.46
Console.WriteLine("L LT {0} KIND={1} ISO={2}",l,l.Kind,l.toISOString());
var t = new DateTime().fromISOString("2018/04/26","14:46:23.456+02:00",true); //12.46Z
Console.WriteLine("T LT+TOFF {0} KIND={1} ISO={2}",t,t.Kind,t.toISOString());
var c = new DateTime().fromISOString("2018-04-26","14:46:23.456Z",true); //14.46Z -> LT=16.46
Console.WriteLine("C UTC->LT {0} KIND={1} ISO={2}",c,c.Kind,c.toISOString());

When you want to pass DateTime to JSON / Javascript simply serialize the value using toISOString()

//USING Date OBJECT IN JAVASCRIPT 
const strUTC = "2018-04-26T14:46:23.456Z"; //String serialized with extension method DateTime.toISOString(); //UTC
const strLocal = "2018-04-26T16:46:23.456+02:00";  //String serialized with DateTime.toISOString(true); //LT+TIMEOFFSET

Date.parse(strUTC); 
//-> 1524753983456
Date.parse(strLocal)
//-> 1524753983456
new Date(strUTC).toISOString()
//-> "2018-04-26T14:46:23.456Z"
new Date(strLocal).toISOString()
//-> "2018-04-26T14:46:23.456Z"
@andreadottor

This comment has been minimized.

Copy link

@andreadottor andreadottor commented Apr 24, 2018

I suggest to rename the methods in camel-casing for respect the Microsoft naming guideline (seeing that the file is c#)
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions

@mmalka

This comment has been minimized.

Copy link

@mmalka mmalka commented Nov 3, 2020

You meant Pascal Casing ?

Note: C# support new DateTime(string), and for a ISO string, a ToString("o") is enough, isn't it?

@dmorosinotto

This comment has been minimized.

Copy link
Owner Author

@dmorosinotto dmorosinotto commented Nov 3, 2020

Hi @mmalka yes I think that for toISOString can be simplified with the ToString("o") formatting, I don't know when it was added, I'm pretty sure that 2 year ago it wasn't available, so I create this Extension method to simplify my works to correctly format and parse ISO-8601 format in C#

PS: do you know if there is something like the "o" format even to simplify the parse?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.