Skip to content

Commit 0bc8773

Browse files
committed
Add DateTime/DateTimeOffset documentation. Fixes #176
1 parent cd6a40b commit 0bc8773

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
date: 2020-02-08
3+
title: DateTime Storage
4+
weight: 20
5+
menu:
6+
main:
7+
parent: troubleshooting
8+
---
9+
10+
# DateTime Storage
11+
12+
MySQL cannot store all the information from a `DateTime` or `DateTimeOffset` value,
13+
so the following considerations should be kept in mind when storing `DateTime` and
14+
`DateTimeOffset` values in MySQL `DATETIME` or `TIMESTAMP` columns.
15+
16+
## MySQL Column Types
17+
18+
There are two MySQL column types for date values: `TIMESTAMP` and `DATETIME`.
19+
20+
The [MySQL documentation](https://dev.mysql.com/doc/refman/8.0/en/datetime.html) should be consulted
21+
to understand the behavior of these two column types, particularly around:
22+
23+
* Range: `1970-01-01 00:00:01` to `2038-01-19 03:14:07` for `TIMESTAMP`; `1000-01-01` to `9999-12-31` for `DATETIME`.
24+
* Time zones: `TIMESTAMP` values will be converted to UTC for storage and from UTC for retrieval, which can lead to reading different values.
25+
26+
## Range and DateTime.MinValue/MaxValue
27+
28+
`DateTime.MinValue` and `DateTime.MaxValue` both exceed the range of a `DATETIME` column
29+
(and are well outside the range of a `TIMESTAMP` column).
30+
31+
`DateTime.MinValue` is `0001-01-01 00:00:00`, but the minimum supported value for a `DATETIME`
32+
column is `1000-01-01 00:00:00`. In many versions of MySQL Server, you _can_ successfully
33+
insert this value; however, [it is not officially supported](https://bugs.mysql.com/bug.php?id=2106).
34+
35+
By default, inserting `DateTime.MaxValue` into a `DATETIME` column will fail with a "datetime field
36+
overflow" error, because the timestamp is `23:59:59.9999999` but `DATETIME` can't store fractional
37+
seconds. To fix this, declare the column as `DATETIME(6)`.
38+
39+
## DateTime Notes
40+
41+
The `DateTime.Kind` property cannot be round-tripped. By default, all `DateTime` values read from
42+
MySQL will have a `Kind` property of `DateTimeKind.Unspecified`.
43+
44+
A best practice is to ensure that only UTC values are stored in a `DATETIME` column, to avoid
45+
data loss when reading or comparing values across different timezones. To enforce this,
46+
set `DateTimeKind=Utc` in the connection string. When this is set, all values will be retrieved
47+
as `DateTimeKind.Utc`, and it is an error to insert `DateTimeKind.Local` values.
48+
49+
Conversely, this connection string option can also be set to `DateTimeKind=Local` to force
50+
the storage and retrieval of only local values.
51+
52+
## DateTimeOffset Notes
53+
54+
It is not possible to store a `DateTimeOffset` in a `DATETIME` column. If you create a
55+
`MySqlParameter` with a `Value` holding a `DateTimeOffset`, only the `UtcDateTime`
56+
property will be stored in MySQL. The recommended approach to store and retrieve
57+
`DateTimeOffset` values is to use two columns: one for the `LocalDateTime` and one
58+
for the `Offset`.
59+
60+
### DateTimeOffset Table Schema
61+
62+
```sql
63+
CREATE TABLE times (
64+
LocalDateTime DATETIME(6),
65+
Offset TIME
66+
);
67+
```
68+
69+
### Storing a DateTimeOffset
70+
71+
```csharp
72+
DateTimeOffset dto;
73+
using var cmd = connection.CreateCommand();
74+
cmd.CommandText = "insert into times(LocalDateTime, Offset) values(@LocalDateTime, @Offset);";
75+
cmd.Parameters.AddWithValue("@LocalDateTime", dto.LocalDateTime);
76+
cmd.Parameters.AddWithValue("@Offset", dto.Offset);
77+
cmd.ExecuteNonQuery();
78+
```
79+
80+
### Reading a DateTimeOffset
81+
82+
```csharp
83+
using var cmd = connection.CreateCommand();
84+
cmd.CommandText = "select LocalDateTime, Offset from times;";
85+
using var reader = cmd.ExecuteReader();
86+
while (reader.Read())
87+
{
88+
var dto = new DateTimeOffset(reader.GetDateTime(0), reader.GetTimeSpan(1));
89+
}
90+
```

0 commit comments

Comments
 (0)