13

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

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

以下是一些美国英语的例子

  1. 2009 年 8 月 - 9 月
  2. 2009 年 8 月
  3. 2009 年 8 月 1 日至 9 日
  4. 2009 年 1 月 1 日至 3 月 3 日
  5. 2009 年 12 月 6 日 - 2010 年 1 月 8 日

形成我可以告诉.NET 框架支持本地化日期,但不支持日期范围。

使用支持System.Globalization.DateTimeFormatInfo的 Windows 语言环境中的信息CultureInfo,我能够(大部分时间)弄清楚如何执行项目 #1 和 #2。第 2 项只是DateTime.ToString(DateTimeFormatInfo.YearMonthFormat). 使用YearMonthFormat我还能够推断出大多数语言用于#1 的格式。对于一些我不能复制的年份。

不幸的是,我不知道如何使用 .NET Framework 来执行项目 #3-#5。Outlook 格式范围使用这些格式,所以我希望可能有一些 Win32 API 可以做到这一点,但谷歌搜索“Win32 日期范围本地化”没有任何用处。

我喜欢“智能范围格式化”提供的增强可用性,并且我希望我的客户不使用英文版 Windows 也能获得同样的好处。

有谁知道如何以一种依赖文化的方式做到这一点?

4

3 回答 3

1

好问题,它似乎确实是 .NET 框架和其他语言似乎也缺少的东西。我猜结果的呈现取决于您的应用程序。

Outlook 作为输入具有非常好的日期理解能力(就像谷歌日历一样),但我个人还没有看到这种形式的表达作为输出(例如显示给用户)。

一些建议:

  1. 坚持显示开始日期和结束日期,不用担心冗余
  2. 自己动手...... :-(

我猜想,从您的术语“本地化”中,您计划将输出国际化,如果是这种情况,您将很难捕捉所有案例,它似乎不是存储在大多数典型案例中的信息国际化数据集。

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

  1. 年份始终显示。
  2. 也总是显示月份(至少其中一个)。
  3. 在情况 3 中不显示天数,我的条件是表示开始日期是 1 日,结束日期是 31 日(例如每月的每一天)
  4. 如果开始/结束的月份不同,则会显示日和月。
  5. 如果两个日期的年份不同,则另外会针对开始日期显示年份。

我知道上面只是看英文,但在我看来,滚动自己看起来并不难,但是在这个编辑器中写太多了!

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

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

这产生与原始问题相同的输出(几乎,在我的九月变成九月):

August - September, 2009
August 1 - 31, 2009
August 1 - 9, 2009
January 1 - March 3, 2009
December 6, 2009 - January 8, 2010
于 2009-07-22T07:06:45.060 回答
1

我最终为此定义了自己的范围格式。

在大多数情况下,我从 LongDatePattern 派生了它们。在可能的情况下,我根据 Google 日历和/或母语人士验证了格式。

我还为时间范围(在同一天)生成了 2 种格式,一种用于同一 12 小时内,另一种用于同一 12 小时外的时间(对于使用 24 小时时间的文化,这两种格式是相同的)。这些主要基于 FullDateTimePattern。

在所有情况下,我尽可能从所有格式中删除“日期名称”(星期一、星期二等)。

我很想在这里发布它们,但似乎 Stack Overflow 的人对 html 表格有一种非理性的恐惧,因为他们不允许表格标签。数据本质上是一个巨大的表格。我没有兴趣尝试使用 CSS 模拟表格,所以我只是将表格放在我自己的网站上。如果您有兴趣,可以在这里访问它:

http://www.transactor.com/misc/ranges.html

如果你真的感兴趣的话,我确实有一些关于我是如何导出许多格式的详细说明,包括哪些经过验证,哪些没有经过验证。如果您想要这些笔记,只需发送电子邮件至:

联系人@transactor.com

我很乐意把它们寄给你。

于 2009-07-26T02:22:37.040 回答
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));
}
于 2009-07-22T12:49:38.513 回答