本地化日期范围

发布于 2024-07-28 23:24:48 字数 833 浏览 1 评论 0原文

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

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

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

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

从我看来,.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 日期范围本地化”没有产生任何有用的结果。

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

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

Does anyone know how to localize date ranges using C#?

In particular, I want to generate "smart" date ranges, so that redundant information is eliminated.

Here are some examples in US English

  1. August - Sept, 2009
  2. August 2009
  3. August 1 - 9, 2009
  4. January 1 - March 3, 2009
  5. December 6, 2009 - January 8, 2010

Form what I can tell the .NET Framework has support for localizing dates, but not ranges of dates.

Using the information in System.Globalization.DateTimeFormatInfo for the Windows locales that CultureInfo supports, I was able to figure out (most of the time) how to do items #1 and #2. Item #2 is just DateTime.ToString(DateTimeFormatInfo.YearMonthFormat). Using YearMonthFormat I was also able to deduce formats to use for #1 for most languages. For the few that I couldn't I just duplicate the year.

Unfortunately, I can't figure out how to do items #3-#5 using the .NET Framework. Outlook formats ranges using those formats, so I was hoping there might be some Win32 APIs that would do it, but a Google search for "Win32 Date Range localization" yielded nothing useful.

I like the enhanced usability provided by "smart range formating", and I would like my customers that are not using English versions of Windows to get the same benefits.

Does any one know how to do that in a culture-dependent manner?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

就是爱搞怪 2024-08-04 23:24:48

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

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

一些建议:

  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

Good question and it does seem to be something that the .NET framework and other languages seem to be missing too. I would guess the presentation of the results depends upon your application.

Outlook has very good date understanding as an input (as does Google calenders), but I haven't personally seen this form of expression as an output (e.g. displayed to the user).

Some recommendations:

  1. Stick with displaying a start date and an end date and don't worry about redundancy
  2. Roll your own..... :-(

I would guess that from your term 'localize' you plan to internationalize the output, if that is the case you are going to have a hard job catching all of the cases, it doesn't seem to be information stored in most of the typical internationalization data sets.

Concentrating on English from your example, you seem to have a number of rules already defined in the code:

  1. Year always displayed.
  2. Month (at least one of them) is also always displayed.
  3. Days are not displayed in case 3, this I would condition to mean that the start date is the 1st and the end is the 31st (e.g. every day of the month)
  4. Day and Month are shown if the start/end are different months.
  5. Year is additionally shown against the start date if the two dates differ by year.

I know the above is only looking at English, but in my view, it doesn't look too hard to roll yourself, too much to write in this editor though!

EDIT - I know this doesn't answer the original - but if anyone using a search engine finds this question and wants an English version...

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

This yields the same output (almost, Sept becomes September in mine) as the original question:

August - September, 2009
August 1 - 31, 2009
August 1 - 9, 2009
January 1 - March 3, 2009
December 6, 2009 - January 8, 2010
夏九 2024-08-04 23:24:48

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

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

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

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

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

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

如果您真的感兴趣,我确实有一些关于如何导出许多格式的详细注释,包括哪些已验证,哪些尚未验证。 如果您需要这些注释,只需发送电子邮件至:

[email protected]

我很乐意将它们发送给您。

I ended up defining my own range formats for this.

For the most part I derived them from the LongDatePattern. Where possible I verified the formats against Google Calendar, and / or native speakers.

I also generated 2 formats for time ranges (within the same day), one for within the same 12 hour period and another for times outside the same 12 hour period (for cultures that use 24 hour time these 2 formats are the same). Those are mostly based on the FullDateTimePattern.

In all cases I removed "day names" (monday, tuesday, etc) from all the formats where ever possible.

I would love to post them here, but it seems that the Stack Overflow folks have an irrational fear of html tables, because they don't allow table tags. The data is essentially a giant table. I have no interest in trying to simulate tables using CSS, so I just put the table up on my own site. You can access it here if you are interested:

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

I do have some detailed notes on how I derived a lot of the formats, including what's been validated and what hasn't, if you are really interested. If you want those notes, just send an email to:

[email protected]

and I'd be happy to send them to you.

独守阴晴ぅ圆缺 2024-08-04 23:24:48

如果我正确理解你的代码,下面的代码处理 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));
}

The below code handles 4 and 5 if I get the idea of your code correctly

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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文