Skip to content

Instantly share code, notes, and snippets.

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) {
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);

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);
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());
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()

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

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

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#)


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?


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.