6

I'm new to NodaTime and I would like to implement it in my application.

How can I parse date string to NodaTime Object?

Here's what I currently have:

var dateInput = "06/11/2015";
var pattern = InstantPattern.CreateWithInvariantCulture("dd/MM/yyyy");
var parseResult = pattern.Parse(dateInput);
var localDate = parseResult.Value;
DateTimeZone tzNZ = DateTimeZoneProviders.Tzdb["Asia/Hong_Kong"];
ZonedDateTime result = localDate.InZone(tzNZ);

my localDate variable is now 2015-11-06T00:00:00Z (and based on what I read in ISO Format, having Z in last part indicated that it's UTC)

my result variable is now 2015-11-06T13:00:00 NZ (+13)

But I'm not sure if I'm in the right path.

Here's what I really want.

  1. Convert the dateInput (date string) to a NodaTime object with the following format dd/MM/yyyy
  2. And then have it as UTC then convert to a long data type then save it to the database
  3. Then try to retrieve the saved data then use a specific timezone. Say Asia/Hong_Kong

Is it possible?

EDIT

var dateInput = "06/11/2015";
var pattern = LocalDatePattern.CreateWithInvariantCulture("dd/MM/yyyy");
LocalDate parseResult = pattern.Parse(dateInput).Value;
DateTimeZone tzHK = DateTimeZoneProviders.Tzdb["Asia/Hong_Kong"];
LocalTime time = GetTimeOfDay();
LocalDateTime localDateTime = parseResult + time;

// change it to UTC then convert it to 
// long data type then save it to the database

// methods
private LocalTime GetTimeOfDay()
{
  var instant = SystemClock.Instance.Now;
  var tz = DateTimeZoneProviders.Tzdb["Asia/Hong_Kong"];

  return instant.InZone(tz).TimeOfDay;
}

I have this snippet and this scenario where the user can only input date say 06/11/2015 then upon saving it to the database, I need it's current time (current time of the user) for viewing purposes. The reason why I am converting it to long is because I am using Entity Framework.

Is this advisable?

Boy Pasmo
  • 8,021
  • 13
  • 42
  • 67
  • Question on your edit - Why would you have them enter a date at all in this scenario? That sounds like you're timestamping the order with the current date and time. – Matt Johnson-Pint Nov 02 '15 at 01:53
  • @MattJohnson This is just an idea I came up. and I just realize it doesn't make any sense. I think I need to delete it. – Boy Pasmo Nov 02 '15 at 02:04
  • Yeah, if you were just timestamping, then none of the rest of this applies, as you would just use `SystemClock.Instance.Now` to get the current UTC-based `Instant`. Or just use `DateTime.UtcNow`, or similar function in your db, and then you wouldn't need Noda Time at all. – Matt Johnson-Pint Nov 02 '15 at 02:50

1 Answers1

5

I'll answer from a slightly different perspective. You said you were converting to long because you were using Entity Framework. That's probably not necessary.

It sounds like you are simply trying to round-trip a calendar date. If there's no specific time involved (such as midnight, or start-of-day), and you want all users to see the same year month and day regardless of which time zone they are in, then it would be better (IMHO) to keep things in those terms throughout the entire process.

Some would argue against this, with common best practice to be "always store in UTC", but that advice doesn't hold up in two common scenarios:

  1. "I've got a local date and time, but they're in the future and I'm using them for scheduling purposes."

  2. "I'm just working with a calendar date without any time of day, it may be past present or future, but it's a human-centric civil date, rather than an unique instant in time."

You appear to be in the second case. So:

  • Use a date-only type in your database, such as the DATE type available in SQL Server, PostgreSQL, MySQL, Oracle, and most other relational databases.

  • Use a LocalDate type in Noda Time. Don't try to convert it to Instant, LocalDateTime, ZonedDateTime, or long.

  • Use a DateTime type (with .Kind == DateTimeKind.Unspecified) to act as an intermediary between the database and your LocalDate property. This is commonly done with the "buddy properties" pattern, as seen in this answer.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Note, I'm making several assumptions in my answer. If you're actually not just trying to round-trip a calendar date, then let me know and I'll delete or revise my response. thanks. – Matt Johnson-Pint Nov 01 '15 at 19:27
  • Oh, so I could use something like your approach to use `DATE` and store `DATE` only in the database and don't worry about the rule "always store in UTC"? I always thought and based on what I read,that you should always store in UTC. I never thought there was an exception. I'm not really sure what is `round-trip a calendar date` is. – Boy Pasmo Nov 02 '15 at 00:57
  • Yes, that's what I mean. "round-trip" is the idea that you get the exact value back that you saved or transmitted. It starts as the string `"2015-11-01"`, gets saved to the database as `2015-11-01`, and can be loaded from the database with the same value. (Something that doesn't round trip would be like setting `DateTimeKind.Utc`, which isn't saved to the database, so would be `DateTimeKind.Unspecified` on return.) – Matt Johnson-Pint Nov 02 '15 at 01:47
  • "always store UTC" is shortsighted, as not all date / time values are an exact timestamp. If you're storing a specific timestamp, such as `2015-11-01T00:00:00-07:00`, then that could be converted to UTC for storage as `2015-11-01T07:00:00Z`, and then easily projected into any time zone from there. But when all you have is a date, then that's not quite the same thing as a timestamp. – Matt Johnson-Pint Nov 02 '15 at 01:50
  • Why use `DateTimeKind.Unspecified` ? What about `DateTimeKind.Local`? And also, does it really matter? I agree that always store as UTC is not a great idea. You lose information, if the request included an offset. – onefootswill Aug 31 '21 at 00:52