How to display DateTime with an abbreviated Time Z

2019-01-17 14:19发布

I am aware of the System.TimeZone class as well as the many uses of the DateTime.ToString() method. What I haven't been able to find is a way to convert a DateTime to a string that, in addition to the time and date info, contains the three-letter Time Zone abbreviation (in fact, much the same way StackOverflow's tooltips for relative time display works).

To make an example easy for everyone to follow as well as consume, let's continue with the StackOverflow example. If you look at the tooltip that displays on relative times, it displays with the full date, the time including seconds in twelve-hour format, an AM/PM designation, and then the three-letter Time Zone abbreviation (in their case, Coordinated Universal Time). I realize I could easily get GMT or UTC by using the built-in methods, but what I really want is the time as it is locally — in this case, on a web server.

If our web server is running Windows Server 2k3 and has it's time zone set to CST (or, until daylight saving switches back, CDT is it?), I'd like our ASP.NET web app to display DateTimes relative to that time zone as well as formatted to display a "CST" on the end. I realize I could easily hard-code this, but in the interest of robustness, I'd really prefer a solution based on the server running the code's OS environment settings.

Right now, I have everything but the time zone abbreviation using the following code:

myDateTime.ToString("MM/dd/yyyy hh:mm:ss tt")

Which displays:

10/07/2008 03:40:31 PM

All I want (and it's not much, promise!) is for it to say:

10/07/2008 03:40:31 PM CDT

I can use System.TimeZone.CurrentTimeZone and use it to correctly display "Central Daylight Time" but... that's a bit too long for brevity's sake. Am I then stuck writing a string manipulation routine to strip out white-space and any non-uppercase letters? While that might work, that seems incredibly hack to me...

Googling and looking around on here did not produce anything applicable to my specific question.

8条回答
Bombasti
2楼-- · 2019-01-17 14:41

If you are using <= .Net 3.0 then download TZ4Net and use OlsonTimeZone.CurrentTimeZone.StandardAbbreviation for > .Net 3.0 use NodaTime or other. The timezones names do not conform to any convention where you can rely on simple string manipulation to construct the abbreviation from an acronym. Wrong 5% of the time is still wrong.

查看更多
Bombasti
3楼-- · 2019-01-17 14:47

I would create a lookup table that converts time zone name to its abbreviation. If the match is not found you could return full zone name.

See time zone abbreviations.

查看更多
Bombasti
4楼-- · 2019-01-17 14:47

Use nodatime.

The following function takes a DateTime in UTC time and formats it with abbreviated local system timezone. Use x in format string for abbreviated timezone. Look for custom formatting here.

    public static string ConvertToFormattedLocalTimeWithTimezone(DateTime dateTimeUtc)
    {
        var tz = DateTimeZoneProviders.Tzdb.GetSystemDefault(); // Get the system's time zone
        var zdt = new ZonedDateTime(Instant.FromDateTimeUtc(dateTimeUtc), tz);
        return zdt.ToString("MM'/'dd'/'yyyy' 'hh':'mm':'ss' 'tt' 'x", CultureInfo.InvariantCulture);
    }
查看更多
该账号已被封号
5楼-- · 2019-01-17 14:54

It depends on the level of robustness that you need.

You'll probably need some kind of hack either way. An easy way would be to split the string by spaces and then concatenate the first letter of each word. i.e.

string[] words = tzname.Split(" ".ToCharArray());
string tzabbr = "";
foreach (string word in words)
   tzabbr += word[0];

That won't work for every time zone on the planet, but it will work for most of them. If you need it more robust then you'll probably need to create a map that maps time zone names to their abbreviations.

查看更多
我想做一个坏孩纸
6楼-- · 2019-01-17 15:01

Here's my quick hack method I just made to work around this.

public static String TimeZoneName(DateTime dt)
{
    String sName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(dt) 
        ? TimeZone.CurrentTimeZone.DaylightName 
        : TimeZone.CurrentTimeZone.StandardName;

    String sNewName = "";
    String[] sSplit = sName.Split(new char[]{' '});
    foreach (String s in sSplit)
        if (s.Length >= 1)
            sNewName += s.Substring(0, 1);

    return sNewName;
}
查看更多
Juvenile、少年°
7楼-- · 2019-01-17 15:01

If pulling the abbreviation from the DaylightName/StandardName, you're going to be better off building the string using a StringBuilder, for strings are immutable.

    public static string ToCurrentTimeZoneString(this DateTime date)
    {
        string name = TimeZone.CurrentTimeZone.IsDaylightSavingTime(date) ?
            TimeZone.CurrentTimeZone.DaylightName :
            TimeZone.CurrentTimeZone.StandardName;
        return name;
    }

    public static string ToCurrentTimeZoneShortString(this DateTime date)
    {
        StringBuilder result = new StringBuilder();

        foreach (string value in date.ToCurrentTimeZoneString().Split(' '))
        {
            if (value.IsNotNullOrEmptyWithTrim())
            {
                result.Append(char.ToUpper(value[0]));
            }
        }

        return result.ToString();
    }

Of course, an array containing KeyValuePair's is probably best for a multinational company. If you want to shave a few minutes off of a tight deadline, and you are at a US company, this works.

查看更多
登录 后发表回答