преобразовать строку в System.DateTime в F # - PullRequest
8 голосов
/ 09 февраля 2011

если я получаю строку из командной строки, и она выглядит так:

'1-1-2011'

как я могу преобразовать эту строку в объект DateTime в F #?

Ответы [ 3 ]

22 голосов
/ 10 февраля 2011

В зависимости от ваших потребностей, класс .NET DateTime имеет несколько статических методов для преобразования строк в DateTime экземпляры, это DateTime.Parse, DateTime.ParseExact и DateTime.TryParse и их несколько перегрузок. .

@ 7sharp9 продемонстрировал самый простой способ выполнения анализа даты с прямым вызовом метода DateTime.Parse. Но в F # все становится интереснее с DateTime.TryParse. Принимая во внимание, что DateTime.Parse выдает исключение в случае сбоя синтаксического анализа, простейшая перегрузка DateTime.TryParse имеет сигнатуру string * byref<DateTime> -> bool, которая будет возвращать, удастся ли синтаксическому анализу установить аргумент byref для проанализированной даты, если она истинна, или по умолчанию. значение (null в данном случае) в противном случае. Тем не менее, синтаксис для использования этого в F # является громоздким (и на самом деле он не приятен для любого языка .NET), поэтому язык F # был разработан со специальной функцией, которая позволяет намного более приятное соглашение о вызовах для таких методов, как @Thomas Petricek указал вне.

Но даже шаблон возвращаемого типа F # (bool, result) здесь не идеален. В большинстве случаев вам не нужно значение по умолчанию, если анализ не выполняется. Лучшая подпись для DateTime.TryParse будет string -> option<DateTime>. К счастью, мы можем легко расширить DateTime, как нам нравится:

type System.DateTime with 
    static member TryParseOption str =
        match DateTime.TryParse str with
        | true, r -> Some(r)
        | _ -> None

Мы используем вышеуказанное расширение следующим образом:

match System.DateTime.TryParseOption "11/11/11" with 
| Some r -> stdout.WriteLine r
| None -> stdout.WriteLine "none"

Что больше соответствует соглашениям F # (например, List.tryFind). Но даже это может стать «лучше». Обратите внимание, как мы сопоставляем результат анализа try. Используя Partial Active Patterns (конечно!), Мы можем обернуть целый класс пробных разборов и переместить совпадение в регистр совпадений для большей гибкости Возьми следующее

open System
let (|DateTime|_|) str =
    match DateTime.TryParse str with
    | true, dt -> Some(dt)
    | _ -> None

let (|Int|_|) str =
    match Int32.TryParse str with
    | true, num -> Some(num)
    | _ -> None

let (|Float|_|) str =
    match Double.TryParse str with
    | true, num -> Some(num)
    | _ -> None

Используя их, мы можем написать небольшое небольшое консольное приложение:

let rec loop() =
    stdout.WriteLine "
Please select an option:
    1) Parse something
    2) Exit
"
    match stdin.ReadLine() with
    | Int 1 -> 
        stdout.WriteLine "Enter something to parse: "
        match stdin.ReadLine() with
        | Int num -> stdout.WriteLine("Successfully parsed int: {0}", num)
        | Float num -> stdout.WriteLine("Successfully parsed float: {0}", num)
        | DateTime dt -> stdout.WriteLine("Successfully parsed DateTime: {0}", dt)
        | _ -> stdout.WriteLine "Parse Failed!"
        loop()
    | Int 2 -> 
        stdout.WriteLine "Now exiting"
    | _ -> 
        stdout.WriteLine "Invalid option, please try again"
        loop()

Ключевым моментом, на который следует обратить внимание, является вложенное совпадение, где Int, Float, DateTime выполняют свои попытки анализа в пределах одного и того же выражения совпадения.

Есть и другие аккуратные приложения этих активных шаблонов, например, мы можем кратко одновременно фильтровать и отображать список строк дат

> ["11/23/2003"; "not a date"; "1/1/23 23:23pm"] |> Seq.choose(|DateTime|_|);;
val it : seq<DateTime> =
  seq
    [11/23/2003 12:00:00 AM {Date = 11/23/2003 12:00:00 AM;
                             Day = 23;
                             DayOfWeek = Sunday;
                             DayOfYear = 327;
                             Hour = 0;
                             Kind = Unspecified;
                             Millisecond = 0;
                             Minute = 0;
                             Month = 11;
                             Second = 0;
                             Ticks = 632051424000000000L;
                             TimeOfDay = 00:00:00;
                             Year = 2003;};
     1/1/2023 11:23:00 PM {Date = 1/1/2023 12:00:00 AM;
                           Day = 1;
                           DayOfWeek = Sunday;
                           DayOfYear = 1;
                           Hour = 23;
                           Kind = Unspecified;
                           Millisecond = 0;
                           Minute = 23;
                           Month = 1;
                           Second = 0;
                           Ticks = 638082121800000000L;
                           TimeOfDay = 23:23:00;
                           Year = 2023;}]
11 голосов
/ 10 февраля 2011

Чтобы добавить одну приятную вещь к тому, что написал 7sharp9, если вы также хотите обрабатывать сбои, вы можете написать:

match System.DateTime.TryParse "1-1-2011" with
| true, date -> printfn "Success: %A" date
| false, _ -> printfn "Failed!"

Это не очевидно, поскольку метод TryParse имеет byref<DateTime> в качестве последнего аргумента (и он используется с использованием out в C #), но F # позволяет вам вызывать метод следующим образом.

11 голосов
/ 09 февраля 2011

Вы можете сделать это так просто:

let dateTime = System.DateTime.Parse "1-1-2011"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...