YYYYMMDDHHMMSS 的最严格字节表示形式?

发布于 2024-12-03 21:49:06 字数 697 浏览 0 评论 0原文

我需要使用最小数量的字节/字符,用 UTC 日期时间打包字符串。我只需要精确到秒。使用 .NET 4.0,最节省空间的方式来打包它是什么?蜱虫看起来没那么小。

所有想法均表示赞赏。 谢谢。

编辑:感谢 Joel Coehoorn,打包/拆包动作是最好的。谢谢!这是一些证明:

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

I need to pack string with a UTC datetime, using the smallest number of bytes/characters. I only need precision to the second. Using .NET 4.0, what would be the most space-efficient way to pack this down? Ticks doesn't seem all that small.

All ideas appreciated.
Thanks.

EDIT: Thanks to Joel Coehoorn, the pack/unpack move is the best. Thanks! Here is some proof:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

疯了 2024-12-10 21:49:06

也许是 Unix 时间(自 1970 年 1 月 1 日以来的秒数而不是毫秒)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 年之前的日期。

Perhaps a variant on unix time (seconds since 1/1/1970 rather than milliseconds) base64 encoded.

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

Note that all this was done without the aid of an IDE - there's likely a bug or two above. But it should get you started.

This should result in a fixed-width string. Since we're only doing seconds rather than milliseconds, you may find you always have some extra padding in the result that you don't need. You might even be able to get away with an int, rather than a long, which will cut the string in half. Be careful stripping that padding out, though, as the closer you get to 1970 the smaller the number, but the farther you get the larger and the more likely you are to need it. You need to be certain that your date value will fit within the new, smaller range for doing any trimming. For example, the current date fits comfortably within an int, but even 28 years from now will not. UInt32 will get you a little further into the future, but prevent you from using dates before 1970.

﹏雨一样淡蓝的深情 2024-12-10 21:49:06

如果您需要保存一些字节,并且非常确定日期时间范围,则此解决方案可行:

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

它将适合时间表示,在 4 个字节 (int) 中定义的时间范围(从 2011 年到 2013 年)中具有 1 秒精度。然而,在我看来,从维护的角度来看,这确实很糟糕。

If you rellay need to save some bytes, and dead sure about date-time bounds, this solution would work:

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

It will fit time representation, with 1 second precision in defined time bounds (from 2011 till 2013) in 4 bytes (int). However, IMO it's really bad from maintenance perspective of view.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文