Skip to content

SFTP file timestamps in UTC shifts when daylight saving offset changes #415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
stefer opened this issue Apr 4, 2018 · 2 comments
Closed

Comments

@stefer
Copy link

stefer commented Apr 4, 2018

We have built a file synchronization service where we rely on the timestamps of files that we save in a DB.
We use SFTPClient.LastWriteTimeUtc to persist the date and time.

After Sweden changed to summertime, we experienced that files where considered as changed because they had a new time when calling SFTPFile.LastWriteTimeUtc. Files that had persisted 2012-12-01T11:51Z now got 2012-12-01T12:51Z.

It might be a problem with the server, CoreFTP, but I found a potential issue in SSH.NET code as well.

A look in https://github.com/sshnet/SSH.NET/blob/develop/src/Renci.SshNet/Sftp/SftpFileAttributes.cs:

            if ((flag & 0x00000008) == 0x00000008)   //  SSH_FILEXFER_ATTR_ACMODTIME
            {
                var time = stream.ReadUInt32();
                accessTime = DateTime.FromFileTime((time + 11644473600) * 10000000);
                time = stream.ReadUInt32();
                modifyTime = DateTime.FromFileTime((time + 11644473600) * 10000000);
            }

According to the RFC, the times here are unix timestamp, in UTC. These are decoded directly into DateTimes with DateTimeKind.Local in the code above. The accessTime and modifyTime should be in local time, as I understand code elsewhere

According to this article this is how that should be done properly:

public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
    // Unix timestamp is seconds past epoch
    System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
    dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
    return dtDateTime;
}

Note that it creates a DateTime with DateTimeKind.Utc first and then converts that to local time.
This difference might be the cause of my problems.
The article also mentions DateTimeOffset.FromUnixTimeMilliSeconds (source) which can be used together with DateTimeOffset.UtcdateTime to parse these dates.

I also had a look in the ScpClient.NET.cs where I found this code:

    var mtime = long.Parse(match.Result("${mtime}"));
    var atime = long.Parse(match.Result("${atime}"));

   var zeroTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
   modifiedTime = zeroTime.AddSeconds(mtime);
   accessedTime = zeroTime.AddSeconds(atime);

In this case, the times are represented as UTC and this should be correct, I think.

@stefer
Copy link
Author

stefer commented Apr 4, 2018

This will be fixed by #356

@IgorMilavec
Copy link
Collaborator

Fixed by #356

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants