0

I am trying to save an Entity with an ID and an DateTimeOffset in a AzureMobileServicesClient SQLite database in a Xamarin Forms application.

This work fine as long as the time stamp is non ambiguous. When we go from daylight saving to standard time there is a period a time where a time stamp can be ambiguous depending on the timezone. In 2016 in Denmark it is 2:00-3:00 AM October 30th.

I save the Entities DateTimeOffset as UTC, but it saves it as a local timestamp.

When I save an ambiguous time stamp as 2016-10-30 12:30 AM + 0:00 it comes back as 2016-10-30 11:30 AM +0:00. I have tested this for other time zones and it only happens with the ambiguous time during the shift from daylight saving to standard time in that particular time zone.

I have seen the issue fixed for a normal SQLite data base here: http://www.thomaslevesque.com/2015/06/28/how-to-retrieve-dates-as-utc-in-sqlite/
But because i am using AzureMobileSerives the solution don't work in this case.

In this code i initialize the AzureMobileService, save an ambiguous time stamp and then retreive it again, and write out the two times to the screen to see the different output

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; }
}

Becuase this is a Xamarin application i also have some code in the xamarin.ios proejct to initlize the database.

//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;
    }
}

I have tried to use a DateTime instead of DateTimeOffset on the entity and only use DateTimeKind=UTC, but I got the same result.

LJA
  • 1
  • 2
  • How do you store DateTime? As Ticks? – H H Oct 06 '16 at 08:10
  • That is determined by the framework; the entity class has a property Date of type DateTimeOffset. When I inspect the Sqlite database, it is saved as number of seconds since some offset. – LJA Oct 06 '16 at 09:44
  • Right, AsTicks is indeed the default setting. Just wanted to verify that. SqLite has no problems with this so it is indeed an Azure service issue. – H H Oct 06 '16 at 12:31
  • Do you have a complete sample to share? I'd like to take a look in context. – Adrian Hall Oct 07 '16 at 20:16
  • There were some errors in the first code, which is now fixed. The SaveTimeStamp class is not part of my application, but I wrote the class to identify the issue with saving ambiguous timestamps. I converted SaveTimeStamp to static so I hope it contains enough information for you. Let me know if you need more. – LJA Oct 10 '16 at 07:54

1 Answers1

0

This looks like an already reported bug: https://github.com/Azure/azure-mobile-apps-net-client/issues/131

Feel free to follow the bug.

Adrian Hall
  • 7,990
  • 1
  • 18
  • 26
  • Yes, they are related in that DateTime is stored as Local and not UTC in the Sqlite client database. Do you know if this bug is being worked on or when a fix can be expected? – LJA Oct 11 '16 at 14:14
  • It is not currently slated for a release. I'll take a look at it this weekend and see what is involved. It would be helpful if you had a GitHub repo with a frontend and backend with a minimal repro. (Otherwise, I'll have to spend time producing one). If you do, please add it to the issue. – Adrian Hall Oct 11 '16 at 17:33
  • Sorry, I am using mobile apps for an application for a customer and cannot put the entire application in GitHub. – LJA Oct 14 '16 at 08:19
  • Understood. Without a valid repro, we will have to generate one. That takes time, which means any fix will be delayed. – Adrian Hall Oct 14 '16 at 15:12