本地化日期范围

时间:2009-07-22 04:26:54

标签: c# .net datetime date globalization

有谁知道如何使用C#本地化日期范围?

特别是,我希望生成“智能”日期范围,以便消除冗余信息。

以下是美国英语中的一些示例

  1. 8月 - 2009年9月
  2. 2009年8月
  3. 2009年8月1日至9日
  4. 2009年1月1日至3月3日
  5. 2009年12月6日 - 2010年1月8日
  6. 表示我可以告诉.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的客户获得相同的好处。

    是否有人知道如何以文化依赖的方式做到这一点?

3 个答案:

答案 0 :(得分:1)

很好的问题,似乎确实是.NET框架和其他语言似乎也缺失了。我猜想结果的呈现取决于你的申请。

Outlook将日期理解作为输入非常好(与Google日历一样),但我没有亲自将这种表达形式视为输出(例如显示给用户)。

一些建议:

  1. 坚持显示开始日期和结束日期,不用担心冗余
  2. 滚动你自己.....: - (
  3. 我猜你从你的术语'本地化'开始计划将输出国际化,如果是这样的话,你将很难抓住所有的情况,它似乎不是存储在大多数情况下的信息典型的国际化数据集。

    从您的示例中专注于英语,您似乎已经在代码中定义了许多规则:

    1. 始终显示年份。
    2. 也始终显示月份(至少其中一个)。
    3. 在案例3中没有显示天数,这将表示开始日期是第一个,结束是第31个(例如,每月的每一天)
    4. 如果开始/结束的月份不同,则会显示日期和月份。
    5. 如果两个日期按年份不同,则会在开始日期之前显示年份。
    6. 我知道以上只是看英文,但在我看来,看起来并不太难以卷起自己,在这个编辑器中写太多了!

      编辑 - 我知道这不能回答原作 - 但是如果有人使用搜索引擎发现这个问题而想要一个英文版......

      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));
}