85

I have a DateTime stored in universal time (UTC) of value 2010-01-01 01:01:01.

I would like to display it in EST in this format 2010-01-01 04:01:01GMT-04:00, however the 'K' formatter for timezone doesn't work in ToString

2
  • Do you have the time in universal time (UTC) or Greenwich Mean Time (GMT)?
    – Guffa
    Commented Jul 23, 2010 at 23:46
  • 1
    If you use the 'K' as a part of your formatter string on DateTime.UtcNow, it doesn't show the offset, because you're already on the GMT timezone and instead 'Z' is appended to your string. But, if you call it on a local time, it shows the offset correctly. The code for ISO8601 format would be DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'GMT'K", CultureInfo.InvariantCulture) Commented Mar 26, 2021 at 16:57

6 Answers 6

104

Use the "zzz" format specifier to get the UTC offset. For example:

        var dt = new DateTime(2010, 1, 1, 1, 1, 1, DateTimeKind.Utc);
        string s = dt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss \"GMT\"zzz");
        Console.WriteLine(s);

Output: 2009-12-31 19:01:01 GMT-06:00

I'm in the CDT timezone. Make sure the DateTime is unambiguously DateTimeKind.Utc.

1
  • 5
    Keep in mind that all "zzz" does is tack the current environment's timezone offset on the end of the datetime being formatted. It does NOT take into account the DateTimeKind value set for the DateTime. It works for this particular case, but if you're formatting a UTC date, it likely won't turn out like you planned.
    – jpt
    Commented Dec 20, 2021 at 15:37
24

If like myself you happen to need a format like 2018-03-31T01:23:45.678-0300 (no colon in the timezone part), you can use this:

datetime.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz").Remove(26,1)
2
  • 2
    This is quite similar to IS08601 format, for which you can likely just use the O format specifier (O includes the colon and seems to have microsecond precision by default) Commented Jul 31, 2019 at 16:07
  • 2
    Right, that format is exactly like "yyyy-MM-ddTHH:mm:ss.fffffffzzz".
    – Andrew
    Commented Jul 31, 2019 at 21:14
16

This method will return the specified time in Eastern Standard Time (as the question requested), even if EST is not the local time zone:

public string GetTimeInEasternStandardTime(DateTime time)
{
    TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
    DateTimeOffset timeInEST = TimeZoneInfo.ConvertTime(time, easternStandardTime);
    return timeInEST.ToString("yyyy-MM-dd hh:mm:ss tt\" GMT\"zzz");
}

Note: I haven't tested this in a non-English OS. See the MSDN documentation on TimeZoneInfo.FindSystemTimeZoneById.

1
  • 1
    @Sasha That's a good point, this answer before didn't disambiguate between AM and PM. I added the "tt" to the time format string to add the AM/PM. Per your comment, you could alternatively replace "hh" with "HH" to output the hours using a 24-hour clock (from 00 to 23). Commented Mar 6, 2017 at 14:46
7

Something like this works. You could probably clean it up a bit more:

string newDate = string.Format("{0:yyyy-MM-dd HH:mm:ss} GMT {1}", dt.ToLocalTime(), dt.ToLocalTime().ToString("%K"));
4
  • 2
    You, probably, meant HH, not hh.
    – Sasha
    Commented Mar 6, 2017 at 10:42
  • Probably... the "hh" gives the 12-hour-clock result where "HH" gives the military-time result.
    – Robaticus
    Commented Mar 7, 2017 at 13:31
  • 2
    Robaticus, I meant that 12-hour format is incompatible with the rest of your answer, because you don't specify AM/PM. I.e. either t/tt should be added to make hh meaningful (e.g. 02:00 AM, 03:00 PM), or hh should be replaced with HH to produce 24-hour format (e.g. 02:00, 15:00). So the yyyy-MM-dd hh:mm:ss format produces ambiguous output that can't be decoded back :(.
    – Sasha
    Commented Mar 7, 2017 at 14:04
  • 1
    I agree. I'll modify my answer to have the caps... though it is probably a low value change, since the selected answer has "HH"
    – Robaticus
    Commented Mar 8, 2017 at 17:32
2

I think you are looking for the TimeZoneInfo class (see http://msdn.microsoft.com/en-us/library/system.timezoneinfo_members.aspx). It has many static methods to convert dates between time zones.

0

If you use the "zzz" format specifier give you the local time zone offset from UTC, but if you want have the specific time zone offset from UTC you should using ToOffset method.
see more here

The ToOffset method is an alternative to calling the TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) method. It can be useful for performing simple conversions from one time zone to another when the time zones' offsets from Coordinated Universal Time (UTC) are known.

For example

    Console.WriteLine("Local time zone :" + DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz"));
    Console.WriteLine("Iran time zone :" + ((DateTimeOffset)DateTime.Now).ToOffset(TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time").BaseUtcOffset).ToString("yyyy-MM-ddTHH:mm:sszzz"));
    Console.WriteLine("Eastern time zone :" + ((DateTimeOffset)DateTime.Now).ToOffset(TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").BaseUtcOffset).ToString("yyyy-MM-ddTHH:mm:sszzz"));

    //Outputs
    Local time zone :2024-06-21T01:41:15+03:30
    Iran time zone :2024-06-21T01:41:15+03:30
    Eastern time zone :2024-06-20T17:11:15-05:00

In the example above, the output of the first line may change by changing the Local TimeZone setting, but the output of the next two lines is always the same and based on the specific given time zone.

Not the answer you're looking for? Browse other questions tagged or ask your own question.