Самое короткое байтовое представление ГГГГММДДЧЧММСС? - PullRequest
2 голосов
/ 09 сентября 2011

Мне нужно упаковать строку с датой и временем UTC, используя наименьшее количество байтов / символов. Мне нужна только точность до второго. С помощью .NET 4.0, каков будет самый экономичный способ упаковать это? Клещи не кажутся такими маленькими.

Все идеи оценены. Спасибо.

РЕДАКТИРОВАТЬ: Благодаря Джоэлу Коухорну, движение пакет / распаковать является лучшим. Спасибо! Вот некоторые доказательства:

DateTimeOffset nowStamp = DateTimeOffset.UtcNow;
        Console.WriteLine( nowStamp.ToString() );                   // 9/9/2011 2:17:17 PM +00:00
        Console.WriteLine( nowStamp.ToString( "u" ) );              // 2011-09-09 14:17:17Z
        Console.WriteLine( nowStamp.Ticks.ToString() );             // 634511746376767889
        Console.WriteLine( PackDate( nowStamp ) );                  // 7R9qTgAAAAA=
        Console.WriteLine( UnpackDate( PackDate( nowStamp ) ) );    // 9/9/2011 2:17:17 PM +00:00

Ответы [ 2 ]

2 голосов
/ 09 сентября 2011

Возможно, вариант времени unix (секунд с 01.01.1970, а не миллисекунд) в кодировке base64.

//Helpers
private static DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long toUnixTime(this DateTime d)
{
    return (long)((d.ToUniversalTime() - Jan1st1970).TotalMilliseconds);
}

public static string Base64Encode(long toEncode)
{
    return Convert.ToBase64String(BitConverter.GetBytes(toEncode));
}

//Encode
public static string PackDate(DateTime toPack)
{
    return Base64Encode(toPack.toUnixTime()/1000);
}

//Decode
public static DateTime UnpackDate(string toUnpack)
{
    long time = BitConverter.ToInt64(Convert.FromBase64String(toUnpack),0);
    return Jan1st1970.AddSeconds(time); //you may or may not want a "ToLocaltime()" call here.
}

Обратите внимание, что все это было сделано без помощи IDE - вероятно, есть ошибкаили два выше.Но это должно помочь вам начать.

Это должно привести к строке фиксированной ширины.Поскольку мы выполняем только секунды, а не миллисекунды, вы можете обнаружить, что у вас всегда есть дополнительные отступы в результате, которые вам не нужны.Возможно, вам даже удастся использовать int, а не long, который разрезает строку пополам.Будьте осторожны, убирая это отступление, но чем ближе к 1970 году, тем меньше число, но чем дальше, тем больше оно и тем больше вероятность того, что оно вам понадобится.Вы должны быть уверенными , что ваше значение даты будет соответствовать новому, меньшему диапазону для выполнения любой обрезки.Например, текущая дата удобно помещается в пределах int, но даже через 28 лет не будет.UInt32 продвинет вас в будущее, но не позволит использовать даты до 1970 года.

0 голосов
/ 13 сентября 2011

Если вам необходимо перезаписать, чтобы сохранить несколько байтов, и точно знать границы даты и времени, это решение будет работать:

internal class Program
{
    private static DateTime _lbound = new DateTime(2011, 1, 1).ToUniversalTime();
    private static DateTime _ubound = new DateTime(2013, 1, 1).ToUniversalTime();

    private static int Pack(DateTime utcTime)
    {
        var totalSeconds = (_ubound - _lbound).TotalSeconds;
        return (int) (utcTime - _lbound).TotalSeconds;
    }

    private static DateTime Unpack(int packedTime)
    {
        return _lbound.AddSeconds(packedTime);
    }
    private static void Check(DateTime time)
    {
        var unpacked = Unpack(Pack(time));
        var areEquals = Math.Abs((time - unpacked).TotalSeconds) < 1.0;
        Console.WriteLine("Verify: {0} - {1}", time, areEquals);
    }

    static void Main(string[] args)
    {
        Check(_lbound);
        Check(_ubound);
        Check(DateTime.UtcNow);
    }
}

Подходит для представления времени с точностью до 1 секунды в определенные временные рамки (с 2011 по 2013 годы) в 4 байта (целое число). Тем не менее, ИМО это действительно плохо с точки зрения обслуживания.

...