2016-07-16 15 views
2

Ich verwende SQLite.NET mit Erweiterungen in einer UWP-App, um ein Objekt zu speichern, das ein DateTime-Feld enthält, und ich bekomme merkwürdige Ergebnisse. Es scheint, dass Daten mit ein paar Stunden von dem gespeichert werden, was sie sein sollten, manchmal den Tag der DateTime auf den nächsten Tag schiebend.Problem mit SQLite und DateTime Genauigkeit

Ich bin Speichern einer POCO-Klasse Rekord genannt, die die Situation Objekt enthält, das wie dieses

public class Situation 
{ 
    [PrimaryKey, AutoIncrement] 
    public int SituationId { get; set; } 

    public DateTime DateTime { get; set; } 

    public string Description { get; set; } 
} 

The Record Klasse sieht, die Situation enthält SQLite gespeichert wird unter Verwendung durch ein Repository-Muster wie so (ich habe nur die relevanten Methoden enthalten):

internal class Repository<T> : IRepository<T> where T : class 
{ 
    private SQLiteAsyncConnection asyncConn; 

    public Repository(SQLiteAsyncConnection conn) 
    { 
     asyncConn = conn; 
    } 

    public async Task<T> GetByIdAsync(int id) 
    { 
     var entity = await asyncConn.GetWithChildrenAsync<T>(id); 
     return entity; 
    } 

    public async Task InsertOrUpdateAsync(T entity) 
    { 
     await asyncConn.InsertOrReplaceWithChildrenAsync(entity); 
    } 
} 

Schließlich erhalte ich eine AsyncConnection für das Repository eine Connectionmanager-Klasse:

public class ConnectionManager 
{ 
    public static readonly string FileName = "db.sqlite"; 

    private static string path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite"); 

    public static SQLiteAsyncConnection GetAsyncConnection() 
    { 
     var connString = new SQLiteConnectionString(path, storeDateTimeAsTicks: true); 
     var connWithLock = new SQLiteConnectionWithLock(new SQLitePlatformWinRT(), connString); 
     return new SQLiteAsyncConnection(() => connWithLock); 
    } 
} 

Diese AsyncConnection speichert DateTimes als Ticks, von denen ich vermute, dass sie die Ursache des Problems sind.

In einem Fall unmittelbar vor dem Record-Objekt gespeichert wird Repository.InsertOrUpdateAsync verwenden, hat die Situation.DateTime folgende Werte:

Datetime = {2016.07.01 12.59.59}

Ticks = 636029747990010000

jedoch die Datensätze mit Repository.GetByIdAsync ziehen, sind Datetime-Werte wie folgt:

Datetime = {2016.07.01 04.59.59}

Ticks = 636029891990010000

Wie Sie sehen können, etwas im Busch ist mit der Art und Weise SQLite ist die Datetime zu speichern. Das Feld Ticks hat sich geändert, was zu einem neuen Datum geführt hat. Ich bin mir nicht 100% sicher, warum das so ist. Ich weiß, DateTime kann Probleme mit Genauigkeit haben, aber wenn DateTimes als Ticks gespeichert sind, sollte das Ticks-Feld nicht übereinstimmen? Warum werden sie verändert?

Angenommen, ich muss DateTimes als Ticks speichern, wie kann ich dieses Problem beheben? Ich denke nur daran, die DateTime-Stunde auf 12 zu setzen, sodass sie sich um mehrere Stunden erhöhen oder verringern lässt, ohne den Tag zu ändern, aber das ist offensichtlich nicht ideal.

Jede Hilfe wäre willkommen. :)

+0

Was ist der Spaltendatentyp in der Tabelle? –

+0

Haben Sie versucht, DateTimeOffset zu verwenden?Das Problem in Ihrem Fall könnte die Tatsache sein, dass DateTime keine Zeitzoneninformation speichert. –

+1

Es sieht total wie ein Zeitzonenproblem aus. Verwenden Sie UTC-Daten, um Zeitzonenprobleme beim Speichern/Lesen von Daten zu vermeiden. – redent84

Antwort

1

Ich machte eine Demo und mit Ticks, um die DateTime zu speichern. Das gleiche Problem tritt auf. Ich debuggte die DateTime Eigenschaft des empfangenen Situation Objekts. Es stellt sich heraus, DateTime.Kind ist Utc. Es ist also ein Zeitzonenproblem, SQLite konvertiert die DateTime standardmäßig in eine UTC-Zeit. Um das Problem zu beheben, können Sie DateTime.ToLocalTime verwenden, um die richtige Ortszeit zu erhalten.

Hier sind die Codes:

if (situation.DateTime.Kind == DateTimeKind.Utc) 
{ 
    situation.DateTime = situation.DateTime.ToLocalTime(); 
} 
+0

Brilliant! Vielen Dank! :) Da mir die tatsächliche Zeit in meinem Fall egal ist, nehme ich an, ich könnte auch, wie redent84 sagte, alle DateTimes mit einem UTC DateTimeKind versehen, richtig? Alles, was mir wichtig ist, sind das Jahr, der Monat und der Tag. Die Zeit war nur ein Problem, da es manchmal den Tag um 1 vorrückte. – AndrewPno

+0

Ich verstehe es nicht. Wenn Sie sich für Tag, Monat und Jahr der Ortszeit interessieren, sollte UTC Datetime auf Ortszeit umgerechnet werden. In bestimmten Szenarien werden Tag Monat oder Jahr nicht korrekt von UTC angezeigt. z.B. 6:00 Uhr 1. Januar 2016 (lokal in China) ist 23:00 Uhr 31. Dezember 2015 (UTC). –