有谁知道如何使用C#本地化日期范围?
特别是,我希望生成“智能”日期范围,以便消除冗余信息。
以下是美国英语中的一些示例
表示我可以告诉.NET Framework支持本地化日期,但不支持日期范围。
将System.Globalization.DateTimeFormatInfo
中的信息用于CultureInfo
支持的Windows语言环境,我能够弄清楚(大多数情况下)如何执行第1项和第2项。第2项只是DateTime.ToString(DateTimeFormatInfo.YearMonthFormat)
。使用YearMonthFormat
我还能够推断出大多数语言用于#1的格式。对于少数我不能,我只是重复这一年。
不幸的是,我无法弄清楚如何使用.NET Framework执行#3-#5项。 Outlook使用这些格式格式化范围,因此我希望可能会有一些Win32 API可以执行此操作,但Google搜索“Win32 Date Range本地化”并没有任何用处。
我喜欢“智能范围格式化”提供的增强可用性,我希望没有使用英文版Windows的客户获得相同的好处。
是否有人知道如何以文化依赖的方式做到这一点?
答案 0 :(得分:1)
很好的问题,似乎确实是.NET框架和其他语言似乎也缺失了。我猜想结果的呈现取决于你的申请。
Outlook将日期理解作为输入非常好(与Google日历一样),但我没有亲自将这种表达形式视为输出(例如显示给用户)。
一些建议:
我猜你从你的术语'本地化'开始计划将输出国际化,如果是这样的话,你将很难抓住所有的情况,它似乎不是存储在大多数情况下的信息典型的国际化数据集。
从您的示例中专注于英语,您似乎已经在代码中定义了许多规则:
我知道以上只是看英文,但在我看来,看起来并不太难以卷起自己,在这个编辑器中写太多了!
class Program
{
static void Main(string[] args)
{
Console.WriteLine(DateRange.Generate(2009, 08, 01, 2009, 09, 31));
Console.WriteLine(DateRange.Generate(2009, 08, 01, 2009, 08, 31));
Console.WriteLine(DateRange.Generate(2009, 08, 01, 2009, 08, 09));
Console.WriteLine(DateRange.Generate(2009, 01, 01, 2009, 03, 03));
Console.WriteLine(DateRange.Generate(2009, 12, 06, 2010, 01, 08));
// Same dates
Console.WriteLine(DateRange.Generate(2009, 08, 01, 2009, 08, 01));
}
}
static class DateRange
{
private static string[] Months = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};
public static string Generate(
int startYear, int startMonth, int startDay,
int endYear, int endMonth, int endDay)
{
bool yearsSame = startYear == endYear;
bool monthsSame = startMonth == endMonth;
bool wholeMonths = (startDay == 1 && IsLastDay(endDay, endMonth));
if ( monthsSame && yearsSame && startDay == endDay)
{
return string.Format("{0} {1}, {2}", startDay, Month(startMonth), startYear);
}
if (monthsSame)
{
if (yearsSame)
{
return wholeMonths
? string.Format("{0} {1}", Month(startMonth), endYear)
: string.Format("{0} {1} - {2}, {3}", Month(endMonth), startDay, endDay, endYear);
}
return wholeMonths
? string.Format("{0}, {1} - {2}, {3}",
Month(startMonth), startYear,
Month(endMonth), endYear)
: string.Format("{0} {1}, {2} - {3} {4}, {5}",
Month(startMonth), startDay, startYear,
Month(endMonth), endDay, endYear);
}
if (yearsSame)
{
return wholeMonths
? string.Format("{0} - {1}, {2}", Month(startMonth), Month(endMonth), endYear)
: string.Format("{0} {1} - {2} {3}, {4}",
Month(startMonth), startDay,
Month(endMonth), endDay,
endYear);
}
return wholeMonths
? string.Format("{0}, {1} - {2}, {3}",
Month(startMonth), startYear,
Month(endMonth), endYear)
: string.Format("{0} {1}, {2} - {3} {4}, {5}",
Month(startMonth), startDay, startYear,
Month(endMonth), endDay, endYear);
}
private static string Month(int month)
{
return Months[month - 1];
}
public static bool IsLastDay(int day, int month)
{
switch (month+1)
{
case 2:
// Not leap-year aware
return (day == 28 || day == 29);
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
return (day == 31);
case 4: case 6: case 9: case 11:
return (day == 30);
default:
return false;
}
}
}
这产生了与原始问题相同的输出(几乎,9月在我的9月):
August - September, 2009
August 1 - 31, 2009
August 1 - 9, 2009
January 1 - March 3, 2009
December 6, 2009 - January 8, 2010
答案 1 :(得分:1)
我最终为此定义了自己的范围格式。
在大多数情况下,我是从LongDatePattern派生出来的。我尽可能根据Google日历和/或以母语人士的身份验证了格式。
我还为时间范围(在同一天内)生成了两种格式,一种用于同一12小时内,另一种用于同一12小时内的时间(对于使用24小时时间的文化,这两种格式是相同的)。这些主要基于FullDateTimePattern。
在所有情况下,我都尽可能从所有格式中删除了“日名”(星期一,星期二等)。
我很想在这里发布它们,但似乎Stack Overflow的人对html表有一种非理性的恐惧,因为它们不允许表标签。数据本质上是一个巨大的表。我没有兴趣尝试使用CSS模拟表,所以我只是将表放在我自己的网站上。如果您有兴趣,可以在此处访问:
http://www.transactor.com/misc/ranges.html
我确实有一些关于我如何得出很多格式的详细说明,包括已经验证的内容以及未经验证的格式,如果你真的感兴趣的话。如果您需要这些笔记,只需发送电子邮件至:
contact@transactor.com
我很乐意把它们发给你。
答案 2 :(得分:0)
如果我能正确理解你的代码,下面的代码会处理4和5
public string GetDateRangeString(DateTime dt1, DateTime dt2)
{
DateTimeFormatInfo info = new DateTimeFormatInfo();
string format1;
string format2;
format2 = info.YearMonthPattern;
format1 = dt1.Year == dt2.Year ? format1 = info.MonthDayPattern :
format2;
return string.Format("{0} - {1}", dt1.ToString(format1), dt2.ToString(format2));
}