#c# #sqlite #datetime #xamarin.forms #azure-mobile-services
#c# #sqlite #дата и время #xamarin.forms #azure-mobile-services
Вопрос:
Я пытаюсь сохранить объект с идентификатором и DateTimeOffset в базе данных AzureMobileServicesClient SQLite в приложении Xamarin Forms.
Это работает нормально, если временная метка не является неоднозначной. Когда мы переходим с летнего времени на стандартное, существует период времени, когда временная метка может быть неоднозначной в зависимости от часового пояса. В 2016 году в Дании это 2:00-3:00 утра 30 октября.
Я сохраняю объекты DateTimeOffset как UTC, но он сохраняет их как локальную временную метку.
Когда я сохраняю неоднозначную временную метку как 2016-10-30 12:30 0:00, она возвращается как 2016-10-30 11:30 0:00. Я тестировал это для других часовых поясов, и это происходит только с неоднозначным временем во время перехода с летнего времени на стандартное время в этом конкретном часовом поясе.
Я видел, что проблема исправлена для обычной базы данных SQLite здесь: http://www.thomaslevesque.com/2015/06/28/how-to-retrieve-dates-as-utc-in-sqlite /
Но поскольку я использую AzureMobileSerives, решение в этом случае не работает.
В этом коде я инициализирую AzureMobileService, сохраняю неоднозначную временную метку, а затем восстанавливаю ее снова и выписываю два раза на экран, чтобы увидеть разные выходные данные
public static class SaveTimeStamp
{
public static async Task Save()
{
//Init mobile service Client
var mobileService = new MobileServiceClient(Configuration.MobileAppsUrl);
//init MobileService Database
var dataStore = DependencyService.Get<IDataStore>();
var path = dataStore.GetPath("store.db");
dataStore.CreateFile(path);
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<Entity>();
await mobileService.SyncContext.InitializeAsync(store, StoreTrackingOptions.NotifyLocalAndServerOperations).ConfigureAwait(false);
var entityTable = mobileService.GetSyncTable<Entity>();
//Save entity with ambiguous timestamp
var ambiguousTimestamp = new DateTimeOffset(2016, 10, 30, 0, 30, 0, TimeSpan.Zero); //UTC: 30th of October 12:30 AM 0:00 => DK time:30th of october 2:30 AM 2:00
var entity = new Entity
{
Id = Guid.NewGuid().ToString(),
Timestamp = ambiguousTimestamp
};
Debug.WriteLine("Saving datetime UTC: " entity.Timestamp.UtcDateTime);
await entityTable.InsertAsync(entity).ConfigureAwait(false);
//Fetch saved entity
var refecthedEntities = await entityTable.Where(e => e.Id == entity.Id).ToListAsync();
var refecthedEntity = refecthedEntities.FirstOrDefault();
if (refecthedEntity.Timestamp != ambiguousTimestamp)
{
Debug.WriteLine("Refecthed datetime UTC do not match: " refecthedEntity.Timestamp.UtcDateTime);
}
else
{
Debug.WriteLine("Refecthed datetime UTC: " refecthedEntity.Timestamp.UtcDateTime);
}
//output
//[0:]Saving datetime UTC: 10/30/2016 12:30:00 AM
//[0:]Refecthed datetime UTC do not match: 10/29/2016 11:30:00 PM
}
}
class Entity
{
public string Id { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
Поскольку это приложение Xamarin, у меня также есть некоторый код в проекте xamarin.ios для инициализации базы данных.
//IN Xamarin.IOS
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init(); //Init Azure mobileservies on IOS Current IOS 9.3
SQLitePCL.CurrentPlatform.Init();
LoadApplication(new App());
App.ScreenWidth = (int)UIScreen.MainScreen.Bounds.Width;
App.ScreenHeight = (int)UIScreen.MainScreen.Bounds.Height;
return base.FinishedLaunching(app, options);
}
public override void WillEnterForeground(UIApplication uiApplication)
{
base.WillEnterForeground(uiApplication);
uiApplication.IdleTimerDisabled = true;
}
public override void DidEnterBackground(UIApplication uiApplication)
{
base.DidEnterBackground(uiApplication);
uiApplication.IdleTimerDisabled = false;
}
}
Я попытался использовать DateTime вместо DateTimeOffset для объекта и использовать только DateTimeKind= UTC, но я получил тот же результат.
Комментарии:
1. Как вы храните дату и время? Как тики?
2. Это определяется платформой; класс entity имеет свойство Date типа DateTimeOffset . Когда я проверяю базу данных Sqlite, она сохраняется как количество секунд с момента некоторого смещения.
3. Верно, AsTicks действительно является настройкой по умолчанию. Просто хотел это проверить. У SQLite нет проблем с этим, так что это действительно проблема службы Azure.
4. У вас есть полный образец для совместного использования? Я хотел бы взглянуть в контексте.
5. В первом коде были некоторые ошибки, которые теперь исправлены. Класс SaveTimeStamp не является частью моего приложения, но я написал класс для выявления проблемы с сохранением неоднозначных временных меток. Я преобразовал SaveTimeStamp в статический, поэтому надеюсь, что он содержит достаточно информации для вас. Дайте мне знать, если вам нужно больше.
Ответ №1:
Это похоже на уже сообщенную ошибку: https://github.com/Azure/azure-mobile-apps-net-client/issues/131
Не стесняйтесь следить за ошибкой.
Комментарии:
1. Да, они связаны тем, что дата и время хранятся как локальные, а не UTC в клиентской базе данных Sqlite. Знаете ли вы, исправляется ли эта ошибка или когда можно ожидать исправления?
2. В настоящее время выпуск не запланирован. Я посмотрю на это в эти выходные и посмотрю, что с этим связано. Было бы полезно, если бы у вас был репозиторий GitHub с интерфейсом и серверной частью с минимальным воспроизведением. (В противном случае мне придется потратить время на ее создание). Если вы это сделаете, пожалуйста, добавьте это в проблему.
3. Извините, я использую мобильные приложения для приложения для клиента и не могу поместить все приложение в GitHub.
4. Понятно. Без корректного воспроизведения нам придется его сгенерировать. Это требует времени, что означает, что любое исправление будет отложено.