如何使用区域短日期将 DateTime 转换为字符串
How to convert DateTime to string using Region Short Date
我想以操作系统首选项中指定的格式将 DateTime 输出为字符串。我不想提供明确的格式模式,而是想使用用户在区域面板中定义的任何内容。
例如在我的 Windows 10 系统上,格式定义在 控制面板 > 区域 > 格式如下:
- 短日期:“yyyy-MM-dd”
- 时间短:“HH:mm”
当文件和文件夹在 Windows 资源管理器中显示时,它们的显示格式为:“yyyy-MM-dd HH:mm”。
我应该指出,我使用的是 Unity 2019.4.4。——据我所知,覆盖CurrentCulture 或类似的东西。我已经用“unity3d”标签标记了这个问题,但它可能与 Unity 没有特别相关,除非 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));
}
}
我假设我需要以某种方式访问 OS 区域面板中定义的文化信息并使用它来格式化字符串,但这就是我迷路的地方。
CurrentCulture 似乎使用了“M/d/yyyy”的 ShortDate 和“h:mm tt”的 ShortTime,这不是我在“区域”面板中设置的。
如何以用户指定的格式将 DateTime 输出为字符串并存储在 Windows 的“区域”面板中,而无需提前知道该模式是什么?
最终,我希望字符串的格式与 Windows Explorer 使用的格式相同,类似于“ShortDate ShortTime”。
正如 Martheen 在评论中所述,Unity 编辑器似乎忽略或覆盖了 OS 提供的 CurrentCulture。
更新:
我找到了一个解决方案,可以 return 我正在寻找的数据,我将在下面包含这些数据。首先,我将更详细地描述问题。
在我的Windows10系统上,我的Region设置自定义如下:
- 格式:英语(美国)
- 短日期:“yyyy-MM-dd”
- 短时间:“HH:mm”
- 长时间:“HH:mm:ss”
这些属性的默认“en-US”设置是:
- 格式:英语(美国)
- 短日期:“M/d/yyyy”
- 短时间:“h:mm tt”
- 长时间:“h:mm:ss tt”
我没有自定义“长日期”格式或任何其他设置。
在 Unity 内部,当访问 Thread.CurrentThread.CurrentCulture
时,它似乎 return 正确的文化,但处于默认状态。就好像当 Unity 加载时,它看到正在使用“en-US”,但它随后用默认值覆盖了文化。像这样:
var culture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo(culture.Name);
稍后,当尝试获取短日期和时间格式时,它们 return 默认值而不是我在区域设置中指定的值。
var culture = Thread.CurrentThread.CurrentCulture;
string shortDatePattern = culture.DateTimeFormat.ShortDatePattern; // "M/d/yyyy"
string shortTimePattern = culture.DateTimeFormat.ShortTimePattern; // "h:mm tt"
通过调用 kernel32.dll 中包含的 GetLocaleInfoEx()
方法并传递某些参数,我可以访问系统上活动的实际区域设置。以下方法可以return 短日期、短时间、长时间的格式模式。 GetDateTimeFormat()
return 对我来说是当前文化的短日期和长时间的组合:“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);
}
似乎 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"));
}
我想以操作系统首选项中指定的格式将 DateTime 输出为字符串。我不想提供明确的格式模式,而是想使用用户在区域面板中定义的任何内容。
例如在我的 Windows 10 系统上,格式定义在 控制面板 > 区域 > 格式如下:
- 短日期:“yyyy-MM-dd”
- 时间短:“HH:mm”
当文件和文件夹在 Windows 资源管理器中显示时,它们的显示格式为:“yyyy-MM-dd HH:mm”。
我应该指出,我使用的是 Unity 2019.4.4。——据我所知,覆盖CurrentCulture 或类似的东西。我已经用“unity3d”标签标记了这个问题,但它可能与 Unity 没有特别相关,除非 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));
}
}
我假设我需要以某种方式访问 OS 区域面板中定义的文化信息并使用它来格式化字符串,但这就是我迷路的地方。
CurrentCulture 似乎使用了“M/d/yyyy”的 ShortDate 和“h:mm tt”的 ShortTime,这不是我在“区域”面板中设置的。
如何以用户指定的格式将 DateTime 输出为字符串并存储在 Windows 的“区域”面板中,而无需提前知道该模式是什么?
最终,我希望字符串的格式与 Windows Explorer 使用的格式相同,类似于“ShortDate ShortTime”。
正如 Martheen 在评论中所述,Unity 编辑器似乎忽略或覆盖了 OS 提供的 CurrentCulture。
更新:
我找到了一个解决方案,可以 return 我正在寻找的数据,我将在下面包含这些数据。首先,我将更详细地描述问题。
在我的Windows10系统上,我的Region设置自定义如下:
- 格式:英语(美国)
- 短日期:“yyyy-MM-dd”
- 短时间:“HH:mm”
- 长时间:“HH:mm:ss”
这些属性的默认“en-US”设置是:
- 格式:英语(美国)
- 短日期:“M/d/yyyy”
- 短时间:“h:mm tt”
- 长时间:“h:mm:ss tt”
我没有自定义“长日期”格式或任何其他设置。
在 Unity 内部,当访问 Thread.CurrentThread.CurrentCulture
时,它似乎 return 正确的文化,但处于默认状态。就好像当 Unity 加载时,它看到正在使用“en-US”,但它随后用默认值覆盖了文化。像这样:
var culture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo(culture.Name);
稍后,当尝试获取短日期和时间格式时,它们 return 默认值而不是我在区域设置中指定的值。
var culture = Thread.CurrentThread.CurrentCulture;
string shortDatePattern = culture.DateTimeFormat.ShortDatePattern; // "M/d/yyyy"
string shortTimePattern = culture.DateTimeFormat.ShortTimePattern; // "h:mm tt"
通过调用 kernel32.dll 中包含的 GetLocaleInfoEx()
方法并传递某些参数,我可以访问系统上活动的实际区域设置。以下方法可以return 短日期、短时间、长时间的格式模式。 GetDateTimeFormat()
return 对我来说是当前文化的短日期和长时间的组合:“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);
}
似乎 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"));
}