24923

Tightest Byte Representation of YYYYMMDDHHMMSS?

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

Answer1:

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.

Answer2:

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.

Recommend

  • SQLite DateTime handling in SQLProvider
  • Grepping a batch ping
  • Time zone PHP refresh
  • TimeZoneInfo.ConvertTime from PST to UTC to AEST - off by one hour
  • MongoDB .NET Driver Group By Time Range
  • LockFile with timeout?
  • How to get the current time stamp in PIG
  • IIS and ISAPI-WSGI = very slow
  • Watir-webdriver timing out when asked if element is present?
  • Multiprocessing pool example (parallel) is slower than sequential. Trying to understand pool in pyth
  • date.js Parse method overrides Javascript Parse method
  • How to parse utc date
  • iPhone: 5 seconds video capture
  • toInstant() in Calendar is showing in GMT instead of Local time
  • How to change default timestamp that PHP uses for logging to file?
  • Jackson Java 8 DateTime serialisation
  • Query timeout expired in django-mssql when executing custom SQL directly
  • Convert unix time to week day
  • Excel Date field value differs from c# dateTime by 1 day while reading excel file with EEPlus
  • UITableView takes much longer to load when numberOfRows returns a large number
  • Real Time CountDown Timer In Python
  • Calculate time difference in hh:mm:ss with simple javascript/jquery
  • Is it possible to open regedit and navigate to straight to a specific key using process.start?
  • print() is showing quotation marks in results
  • ActiveRecord query for a count of new users by day
  • Play WS (2.2.1): post/put large request
  • Q promise. Difference between .when and .then
  • How to access EntityManager inside Entity class in EJB3
  • Illegal mix of collations for operation for date/time comparison
  • vba code to select only visible cells in specific column except heading
  • retrieve vertices with no linked edge in arangodb
  • JTable with a ScrollPane misbehaving
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • unknown Exception android
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • failed to connect to specific WiFi in android programmatically
  • How to push additional view controllers onto NavigationController but keep the TabBar?
  • How can I use threading to 'tick' a timer to be accessed by other threads?