114

I have a DateTime which I want to format to "2009-09-01T00:00:00.000Z", but the following code gives me "2009-09-01T00:00:00.000+01:00" (both lines):

new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")
new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")

Any ideas how to make it work?

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Grzenio
  • 35,875
  • 47
  • 158
  • 240

9 Answers9

210
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 2
    @Downvoter: Would you like to tell us what you think is wrong with this answer? – LukeH Oct 21 '14 at 14:31
  • 16
    This worked but the .ToUniversalTime() will mess up your existing date if it is already at UTC but the yourDateTime variable doesn't specify it. I ended up removing the .ToUniversalTime() and the dates then lined up with what was expected at both ends (database and web client). – Robin Vessey Feb 25 '15 at 05:41
  • 14
    If your date time is already universal time, you can call `.ToUniversalTime()` all you want, it will not change it. -- However, if you've got a universal time value stored as a local time, then of course it will change it (but in that case, you've got bigger problems to deal with!) -- Anyway, this answer is terrible. You should use the `"O"` format string as specified by the answer below, instead. – BrainSlugs83 Oct 29 '18 at 03:30
  • 3
    @BrainSlugs83: This "terrible" answer actually gives the OP what they asked for: `2009-09-01T00:00:00.000Z`. Using the "O" specifier would give them something different: `2009-09-01T00:00:00.0000000Z`. – LukeH Sep 18 '19 at 23:05
  • Documentation for custom string formatting for DateTime https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings – Mark Hebert Oct 23 '19 at 21:00
  • 8
    Note that it doesn't need the `'` characters, `"yyyy-MM-ddTHH:mm:ss.fffZ"` would also work and is nicer. – iJungleBoy Jan 18 '21 at 12:55
85

Why don't just use The Round-trip ("O", "o") Format Specifier?

The "O" or "o" standard format specifier represents a custom date and time format string using a pattern that preserves time zone information and emits a result string that complies with ISO 8601. For DateTime values, this format specifier is designed to preserve date and time values along with the DateTime.Kind property in text. The formatted string can be parsed back by using the DateTime.Parse(String, IFormatProvider, DateTimeStyles) or DateTime.ParseExact method if the styles parameter is set to DateTimeStyles.RoundtripKind.

The "O" or "o" standard format specifier corresponds to the "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK" custom format string for DateTime values and to the "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" custom format string for DateTimeOffset values. In this string, the pairs of single quotation marks that delimit individual characters, such as the hyphens, the colons, and the letter "T", indicate that the individual character is a literal that cannot be changed. The apostrophes do not appear in the output string.

The O" or "o" standard format specifier (and the "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK" custom format string) takes advantage of the three ways that ISO 8601 represents time zone information to preserve the Kind property of DateTime values:

public class Example
{
   public static void Main()
   {
       DateTime dat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                   DateTimeKind.Unspecified);
       Console.WriteLine("{0} ({1}) --> {0:O}", dat, dat.Kind); 

       DateTime uDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Utc);
       Console.WriteLine("{0} ({1}) --> {0:O}", uDat, uDat.Kind);

       DateTime lDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Local);
       Console.WriteLine("{0} ({1}) --> {0:O}\n", lDat, lDat.Kind);

       DateTimeOffset dto = new DateTimeOffset(lDat);
       Console.WriteLine("{0} --> {0:O}", dto);
   }
}
// The example displays the following output: 
//    6/15/2009 1:45:30 PM (Unspecified) --> 2009-06-15T13:45:30.0000000 
//    6/15/2009 1:45:30 PM (Utc) --> 2009-06-15T13:45:30.0000000Z 
//    6/15/2009 1:45:30 PM (Local) --> 2009-06-15T13:45:30.0000000-07:00 
//     
//    6/15/2009 1:45:30 PM -07:00 --> 2009-06-15T13:45:30.0000000-07:00
Community
  • 1
  • 1
Dmitry Pavlov
  • 30,789
  • 8
  • 97
  • 121
  • Because it does not work as requested, you quoted it after all -- `"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz"` is not Zulu format. – astrowalker Apr 08 '19 at 06:43
  • @astrowalker It should work. He gave you multiple options in his answer. You need only pick one. In your case (and in the OP's), you would use DateTimeKind.Utc to produce strings with "z" at the end (a.k.a. "Zulu Format" or "UTC Time"). Just look at his example output for UTC. In my case, I used: `dtVariable.ToUniversalTime().ToString("o")` which will convert to `"2019-05-26T19:50:34.4400000Z"` or `"yyyy-MM-ddTHH:mm:ss.fffffffZ"`. Note: I have also tested this with Javscript's `new Date(dtDateString).getTime()` method and it correctly parses the date string produced by this. – MikeTeeVee May 26 '19 at 19:52
  • @MikeTeeVee, I was just pointing out the provided solutions won't work (for DTO). The appropriate way is `dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'")`. For the record, just `"o"` adds offset, it is not Zulu format. – astrowalker May 27 '19 at 06:17
  • 2
    For those trying to do a string transformation: `$"{DateTime.UtcNow:O}"` – Tiago César Oliveira Dec 20 '19 at 10:17
  • To do this conversion in the format requested in the question, use `new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToString("o");` – Chris Halcrow Jan 25 '23 at 03:36
  • 1
    This should now be the accepted answer, as it doesn't rely on correct string formatting to ensure conformance to ISO8601. – Chris Halcrow Feb 15 '23 at 05:01
30
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

returns 2017-02-10T08:12:39.483Z

arviman
  • 5,087
  • 41
  • 48
9

Some people have pointed out that ‘ToUniversalTime’ is somewhat unsafe in that it can cause unintended incorrect time dispalys. Expanding on that I’m providing a more detailed example of a solution. The sample here creates an extension to the DateTime object that safely returns a UTC DateTime where you can use ToString as desired….

class Program
{
    static void Main(string[] args)
    {
        DateTime dUtc = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Utc);
        DateTime dUnspecified = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Unspecified);

        //Sample of an unintended mangle:
        //Prints "2016-06-01 10:17:00Z"
        Console.WriteLine(dUnspecified.ToUniversalTime().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUtc.SafeUniversal().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUnspecified.SafeUniversal().ToString("u"));
    }
}

public static class ConvertExtensions
{
    public static DateTime SafeUniversal(this DateTime inTime)
    {
        return (DateTimeKind.Unspecified == inTime.Kind)
            ? new DateTime(inTime.Ticks, DateTimeKind.Utc)
            : inTime.ToUniversalTime();
    }
}
user3228938
  • 155
  • 1
  • 8
9

This code is working for me:

var datetime = new DateTime(2017, 10, 27, 14, 45, 53, 175, DateTimeKind.Local);
var text = datetime.ToString("o");
Console.WriteLine(text);
--  2017-10-27T14:45:53.1750000+03:00

// datetime from string
var newDate = DateTime.ParseExact(text, "o", null);
Stepan Novikov
  • 1,402
  • 12
  • 22
Ergin Çelik
  • 719
  • 7
  • 14
7

The best format to use is "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK".

The last K on string will be changed to 'Z' if the date is UTC or with timezone (+-hh:mm) if is local. (http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx)

As LukeH said, is good to use the ToUniversalTime if you want that all the dates will be UTC.

The final code is:

string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK");
Carlos Beppler
  • 2,552
  • 1
  • 18
  • 17
6

You want to use DateTimeOffset class.

var date = new DateTimeOffset(2009, 9, 1, 0, 0, 0, 0, new TimeSpan(0L));
var stringDate = date.ToString("u");

sorry I missed your original formatting with the miliseconds

var stringDate = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
Nick Berardi
  • 54,393
  • 15
  • 113
  • 135
0

If you don't mind using Newtonsoft.Json:

string result = JsonConvert.SerializeObject(DateTime.UtcNow, new JsonSerializerSettings
        {
            DateTimeZoneHandling = DateTimeZoneHandling.Utc
        });
cuongle
  • 74,024
  • 28
  • 151
  • 206
-4

Try this:

DateTime date = DateTime.ParseExact(
    "Tue, 1 Jan 2008 00:00:00 UTC", 
    "ddd, d MMM yyyy HH:mm:ss UTC", 
    CultureInfo.InvariantCulture);

Previously asked question

Community
  • 1
  • 1
Ian P
  • 12,840
  • 6
  • 48
  • 70