简体   繁体   English

如何使用区域短日期将 DateTime 转换为字符串

[英]How to convert DateTime to string using Region Short Date

I would like to output a DateTime as a string in the format specified in the operating system preferences.我想 output 以操作系统首选项中指定的格式将 DateTime 作为字符串。 I don't want to provide an explicit format pattern, but instead want to use whatever the user has defined in the Region panel.我不想提供明确的格式模式,而是想使用用户在“区域”面板中定义的任何内容。

For example on my Windows 10 system, formats are defined under Control Panel > Region > Formats as follows:例如在我的 Windows 10 系统上,格式在控制面板>区域>格式下定义如下:

  • Short date: "yyyy-MM-dd"短日期:“yyyy-MM-dd”
  • Short time: "HH:mm"短时间:“HH:mm”

When files and folders are displayed in Windows Explorer, they appear in the format: "yyyy-MM-dd HH:mm".当文件和文件夹显示在 Windows 资源管理器中时,它们的显示格式为:“yyyy-MM-dd HH:mm”。

I should point out that I'm using Unity 2019.4.4.我应该指出,我使用的是 Unity 2019.4.4。 -- As far as I know, it's not doing anything strange by overriding the CurrentCulture or anything like that. - 据我所知,通过覆盖 CurrentCulture 或类似的东西并没有做任何奇怪的事情。 I've tagged this question with the "unity3d" tag, but it may not be specifically related to Unity, unless Unity is doing strange things with the culture.我用“unity3d”标签标记了这个问题,但它可能与 Unity 没有特别的关系,除非 Unity 对文化做了奇怪的事情。

I've tried the following .NET Fiddle , and saw the same results as in Unity:我尝试了以下.NET Fiddle ,并看到了与 Unity 相同的结果:

using System;
using System.Globalization;

public class Program
{
    public static void Main()
    {
        long dateTimeTicks = 637314588165245627;
        DateTime dateTime = new DateTime(dateTimeTicks);

        // I thought the following methods might work, since the Region panel allow configuring the
        // short and long formats for date and time.

        Console.WriteLine(dateTime.ToShortDateString());  // 7/27/2020
        Console.WriteLine(dateTime.ToLongDateString());   // Monday, July 27, 2020
        Console.WriteLine(dateTime.ToShortTimeString());  // 3:00 PM
        Console.WriteLine(dateTime.ToLongTimeString());   // 3:00:16 PM

        // None of the standard date and time format strings work. The "o", "s", and "u" are close to
        // what I'm looking for, but I don't want to force this format, I want to use whatever the
        // user has specified in the Region preferences.

        Console.WriteLine(dateTime.ToString());                                // 7/27/2020 3:00:16 PM
        Console.WriteLine(dateTime.ToString(CultureInfo.CurrentCulture));      // 7/27/2020 3:00:16 PM
        Console.WriteLine(dateTime.ToString(CultureInfo.InvariantCulture));    // 07/27/2020 15:00:16
        Console.WriteLine(dateTime.ToString(CultureInfo.InstalledUICulture));  // 7/27/2020 3:00:16 PM

        Console.WriteLine(dateTime.ToString("d"));  // 7/27/2020
        Console.WriteLine(dateTime.ToString("D"));  // Monday, July 27, 2020
        Console.WriteLine(dateTime.ToString("f"));  // Monday, July 27, 2020 3:00 PM
        Console.WriteLine(dateTime.ToString("F"));  // Monday, July 27, 2020 3:00:16 PM
        Console.WriteLine(dateTime.ToString("g"));  // 7/27/2020 3:00 PM
        Console.WriteLine(dateTime.ToString("G"));  // 7/27/2020 3:00:16 PM
        Console.WriteLine(dateTime.ToString("m"));  // July 27
        Console.WriteLine(dateTime.ToString("o"));  // 2020-07-27T15:00:16.5245627
        Console.WriteLine(dateTime.ToString("r"));  // Mon, 27 Jul 2020 15:00:16 GMT
        Console.WriteLine(dateTime.ToString("s"));  // 2020-07-27T15:00:16
        Console.WriteLine(dateTime.ToString("t"));  // 3:00 PM
        Console.WriteLine(dateTime.ToString("T"));  // 3:00:16 PM
        Console.WriteLine(dateTime.ToString("u"));  // 2020-07-27 15:00:16Z
        Console.WriteLine(dateTime.ToString("U"));  // Monday, July 27, 2020 3:00:16 PM
        Console.WriteLine(dateTime.ToString("y"));  // July 2020

        // I considered using CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern and
        // CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern together, but they also
        // don't return what is specified in Region preferences.

        // 7/27/2020
        Console.WriteLine(dateTime.ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern));
    }
}

I'm assuming I need to somehow access the Culture information that's defined in the OS Regions panel and use that to format the string, but that's where I'm lost.我假设我需要以某种方式访问在 OS Regions 面板中定义的文化信息并使用它来格式化字符串,但这就是我迷路的地方。

The CurrentCulture seems to be using a ShortDate of "M/d/yyyy" and a ShortTime of "h:mm tt", which is not what I have set in my Region panel. CurrentCulture 似乎使用“M/d/yyyy”的 ShortDate 和“h:mm tt”的 ShortTime,这不是我在我的区域面板中设置的。

How can I output the DateTime as a string in the format specified by the user and stored in the Region panel on Windows without knowing what that pattern is ahead of time?我怎么能 output 作为用户指定格式的字符串并存储在 Windows 的区域面板中而不知道该模式是什么提前?

Ultimately, I would like the string to be in the same format used by Windows Explorer, which would be something like "ShortDate ShortTime".最终,我希望字符串与 Windows Explorer 使用的格式相同,类似于“ShortDate ShortTime”。

As Martheen stated in the comment, the Unity editor appears to be ignoring or overriding the CurrentCulture as provided by the OS.正如 Martheen 在评论中所说,Unity 编辑器似乎忽略或覆盖了操作系统提供的 CurrentCulture。


UPDATE:更新:

I found a solution that does return the data that I'm looking for, which I'll include below.我找到了一个解决方案,它确实返回了我正在寻找的数据,我将在下面提供这些数据。 First I'll describe the problem in more detail.首先,我将更详细地描述这个问题。

On my Windows 10 system, my Region settings are customized as follows:在我的 Windows 10 系统上,我的 Region 设置自定义如下:

  • Format: English (United States)格式:英语(美国)
  • Short date: "yyyy-MM-dd"短日期:“yyyy-MM-dd”
  • Short time: "HH:mm"短时间:“HH:mm”
  • Long time: "HH:mm:ss"长时间:“HH:mm:ss”

The default "en-US" settings for those properties are:这些属性的默认“en-US”设置为:

  • Format: English (United States)格式:英语(美国)
  • Short date: "M/d/yyyy"短日期:“M/d/yyyy”
  • Short time: "h:mm tt"短时间:“h:mm tt”
  • Long time: "h:mm:ss tt"长时间:“h:mm:ss tt”

I didn't customize the "Long date" format or any other settings.我没有自定义“长日期”格式或任何其他设置。

Inside Unity, when accessing Thread.CurrentThread.CurrentCulture , it does seem to return the proper culture, but in its default state.在 Unity 内部,当访问Thread.CurrentThread.CurrentCulture时,它似乎确实返回了正确的区域性,但在其默认的 state 中。 It's as if when Unity loads, it sees that "en-US" is being used, but it then overwrites the culture with default values.就好像当 Unity 加载时,它看到正在使用“en-US”,但它随后用默认值覆盖了文化。 Something like this:像这样的东西:

var culture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo(culture.Name);

Later, when trying to get the short date and time formats, they return the default values instead of the values I've specified in Region settings.后来,当尝试获取短日期和时间格式时,它们返回默认值,而不是我在区域设置中指定的值。

var culture = Thread.CurrentThread.CurrentCulture;
string shortDatePattern = culture.DateTimeFormat.ShortDatePattern; // "M/d/yyyy"
string shortTimePattern = culture.DateTimeFormat.ShortTimePattern; // "h:mm tt"

By invoking the GetLocaleInfoEx() method included in kernel32.dll and passing certain parameters, I can access the actual Region settings active on my system.通过调用kernel32.dll中包含的GetLocaleInfoEx()方法并传递某些参数,我可以访问系统上活动的实际区域设置。 The following methods can return the format pattern for the short date, short time, and long time.以下方法可以返回短日期、短时间和长时间的格式模式。 And GetDateTimeFormat() returns for me the combined short date and long time for the current culture: "yyyy-MM-dd HH:mm:ss". GetDateTimeFormat()为我返回当前文化的组合短日期和长时间:“yyyy-MM-dd HH:mm:ss”。

public class LocaleFunctions
{
   public enum LCTYPE : uint
   {
      // There are 150+ values than can be passed to GetLocaleInfoEx(),
      // but most were excluded for brevity.
      //
      // See the following header file for defines with the "LOCALE_" prefix:
      //    https://github.com/wine-mirror/wine/blob/master/include/winnls.h
      //
      LOCALE_SSHORTDATE = 0x001F,
      LOCALE_STIMEFORMAT = 0x1003,
      LOCALE_SSHORTTIME = 0x0079
   }

   public static string GetDateTimeFormat()
   {
      var locale = Thread.CurrentThread.CurrentCulture.Name;
      return GetShortDateFormat(locale) + " " + GetLongTimeFormat(locale);
   }

   public static string GetLongTimeFormat(string locale, int maxLength = 32)
   {
      var data = new StringBuilder(maxLength);
      GetLocaleInfoEx(locale, LCTYPE.LOCALE_STIMEFORMAT, data, maxLength);
      return data.ToString();
   }

   public static string GetShortDateFormat(string locale, int maxLength = 32)
   {
      var data = new StringBuilder(maxLength);
      GetLocaleInfoEx(locale, LCTYPE.LOCALE_SSHORTDATE, data, maxLength);
      return data.ToString();
   }

   public static string GetShortTimeFormat(string locale, int maxLength = 32)
   {
      var data = new StringBuilder(maxLength);
      GetLocaleInfoEx(locale, LCTYPE.LOCALE_SSHORTTIME, data, maxLength);
      return data.ToString();
   }

   // pInvoke declarations
   [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   private static extern int GetLocaleInfoEx(
      string lpLocaleName,
      LCTYPE lcType,
      StringBuilder lpLCData,
      int cchData);
}

It seems that Unity can't get the values directly from the Operating System, but you can still formatting your DateTime as shown below, with all the system options:似乎 Unity 无法直接从操作系统获取值,但您仍然可以使用所有系统选项格式化DateTime ,如下所示:

    System.DateTime currentTime = System.DateTime.Now;

    void Start()
    {
        //Short date
        Debug.Log(currentTime.ToString("M/d/yyyy"));
        Debug.Log(currentTime.ToString("M/d/yy"));
        Debug.Log(currentTime.ToString("MM/dd/yy"));
        Debug.Log(currentTime.ToString("MM/dd/yyyy"));
        Debug.Log(currentTime.ToString("yy/MM/dd"));
        Debug.Log(currentTime.ToString("yyyy-MM-dd"));
        Debug.Log(currentTime.ToString("dd-MMM-yy"));

        //Long date
        Debug.Log(currentTime.ToString("dddd, MMMM d, yyyy"));
        Debug.Log(currentTime.ToString("MMMM d, yyyy"));
        Debug.Log(currentTime.ToString("dddd, d MMMM, yyyy"));
        Debug.Log(currentTime.ToString("d MMMM, yyyy"));

        //Short time
        Debug.Log(currentTime.ToString("h:mm tt"));
        Debug.Log(currentTime.ToString("hh:mm tt"));
        Debug.Log(currentTime.ToString("H:mm"));
        Debug.Log(currentTime.ToString("HH:mm"));

        //Long time
        Debug.Log(currentTime.ToString("h:mm:ss tt"));
        Debug.Log(currentTime.ToString("hh:mm:ss t"));
        Debug.Log(currentTime.ToString("H:mm:ss"));
        Debug.Log(currentTime.ToString("HH:mm:ss"));
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM