【问题标题】:iso 8601 conversion Week in URL 2014-W43URL 2014-W43 中的 iso 8601 转换周
【发布时间】:2014-10-23 14:12:26
【问题描述】:

我正在编写一个 ASP.Net Web Api (2.2)。这是一个报告系统(漂亮的图表和东西)

我想通过上一个/下一个按钮提供数据的日/周/月视图。

我的 URI 路径如下所示:

config.Routes.MapHttpRoute(
   name: "Api UriPathExtension Report DateCategory ISO 8601",
    routeTemplate: "api/{controller}/{dateCategory}/{iso8601date}.{ext}",
    defaults: new
    {
        ext = RouteParameter.Optional
    }
);

我想获取我的 iso8601date 并根据 dateCategory 参数中的值(日/周/月)进行处理。

/// <param name="dateCategory">string {Day/Week/Month}</param>
/// <param name="iso8601date">The iso8601 compliant 
/// date(2014-10-22),
/// week(2014-W43),
/// or month(2014-10)</param>

DateTime date = DateTime.Parse(iso8601date,null,DateTimeStyles.RoundtripKind);

// 2014-10-22 works fine: 2014-10-22T00:00
// 2014-10 works fine: 2014-10-01T00:00
// 2014-W43 throws error: 

An exception of type 'System.FormatException' occurred in mscorlib.dll but was not handled in user code

Additional information: The string was not recognized as a valid DateTime. There is an unknown word starting at index 5.

有什么方法可以将这个 2014-W43 解析为我可以在 JSON.net 序列化中使用的时间。也许与 NodaTime?我似乎找不到任何东西。

我可以构建它,但似乎应该有一个解决方案。根据维基百科,它是part of the iso8601 spec

【问题讨论】:

    标签: asp.net url asp.net-web-api iso8601 nodatime


    【解决方案1】:

    虽然它是 ISO-8601 的一部分,但 .NET 或 Noda Time 没有内置任何东西来解析像 "2014-W43" 这样的值,这是有充分理由的:

    该值代表整个周。解析得到的数据必须是 range 的值。在 Noda Time 中,有 Interval 类型来表示 Instant 值的范围,但没有其他通用范围类型。

    更具体地说,应将整周建模为一个完全包含时区忽略日期的值的范围。使用 Noda Time,您将拥有一对 LocalDate 值。

    如果没有 Noda Time,您将遇到 .NET 没有仅日期数据类型的问题。如果您使用一对DateTime 值和午夜的时间,那么您需要提前一天调整结束日期,并使用半开间隔逻辑,以便开始日期包含但结束日期不包含在内.

    解析本身相当简单,但您将无法使用任何现有的解析器。在这里,这应该可以帮助您入门。我相信您可以完成您可能需要的任何剩余功能:

    public struct LocalDateRange
    {
        public LocalDate StartDate { get; private set; }
        public LocalDate EndDate { get; private set; }
    
        public int LengthInDays
        {
            get
            {
                var period = Period.Between(StartDate, EndDate, PeriodUnits.Days);
                return (int) period.Days + 1;
            }
        }
    
        public LocalDateRange(LocalDate startDate, LocalDate endDate)
            : this()
        {
            StartDate = startDate;
            EndDate = endDate;
        }
    
        public static LocalDateRange ParseFromIsoWeek(string s)
        {
            var m = Regex.Match(s, @"(\d{4})-W(\d{1,2})");
            if (!m.Success)
                throw new FormatException();
    
            var year = int.Parse(m.Groups[1].Value);
            var weekNumber = int.Parse(m.Groups[2].Value);
    
            // Note: ISO8601 weeks run from Monday through Sunday, per spec
            var startDate = LocalDate.FromWeekYearWeekAndDay(
                year, weekNumber, IsoDayOfWeek.Monday);
            var endDate = LocalDate.FromWeekYearWeekAndDay(
                year, weekNumber, IsoDayOfWeek.Sunday);
    
            return new LocalDateRange(startDate, endDate);
        }
    
        public override string ToString()
        {
            return string.Format("[{0} - {1}]", StartDate, EndDate);
        }
    }
    

    调用它很简单,像这样:

    var week = LocalDateRange.ParseFromIsoWeek("2014-W43");
    

    注意,在这个例子中我没有实现相等或比较功能。

    【讨论】:

    • 太棒了。为简单起见,我最终可能会使用实际的开始日期,但这感觉更正确。
    猜你喜欢
    • 2013-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    • 2012-02-13
    相关资源
    最近更新 更多