chrono icon indicating copy to clipboard operation
chrono copied to clipboard

Provide more ways to format the fractional portion of a second (required for X.690/ASN.1)

Open rubdos opened this issue 8 years ago • 8 comments

Hello there,

I'm currently working on a ASN.1 DER serializer. This standard has support for sub-second representation, but they (foolishly) drop significant zeros in their representation.
I currently use

let mut time = format!("{}", time.format("%Y%m%d%H%M%S%f"));
let (prefix, fraction) = time.split_at_mut(14);       
let time = match fraction.as_bytes().iter().enumerate().rfind(|&(_, &x)| x != b'0') {
    Some((offset, _)) => prefix.to_owned() + "." + &fraction[0..offset+1] + "Z",
    None => prefix.to_owned() + "Z",                  
};                 

to generate my output (which is both ugly and inefficient). What it basically does is it prints out the "%f" (nanoseconds) and truncates its zeroes. If there's nothing left, the "." is also omitted.

TL;DR: So: I basically wonder whether it'd be possible for a (preferably more efficient) "%S" like formatter that outputs the seconds, and omits zeroes and the "." when "possible".

rubdos avatar Jun 25 '17 07:06 rubdos

Can't you do something like:

if time.nanosecond() == 0 {
   // fmt without frac
} else {
   // fmt with frac
}

Unless I'm missing something that's what this hypothetical format specifier would do anyway, and increasing the size of the format mini-language for this use case seems like overkill.

quodlibetor avatar Jun 26 '17 15:06 quodlibetor

increasing the size of the format mini-language for this use case seems like overkill.

roger that!

It's not only that though, it's also trimming the trailing zeros of the nanosecond. It's stupid, but the standard requires it.

rubdos avatar Jun 26 '17 20:06 rubdos

Does the if-statement I suggested not fix your performance concerns?

Also, actually, the %.f format (note the .) should already do what you want. I just checked and this passes for me:

assert_eq!(FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 0)
           .format("%.f").to_string(),
           "");

Otherwise I don't actually understand what you want.

quodlibetor avatar Jun 26 '17 20:06 quodlibetor

Oh, wait, you want something that can result in .7 instead of currently you'd end up with .700? So, print the smallest amount possible?

If so I take it back that sounds pretty reasonable. I think maybe some sort of %.-f format would work?

quodlibetor avatar Jun 26 '17 20:06 quodlibetor

This seems a reasonable request. The actual sequence is up to bikeshedding though... %#.f might work, assuming that we are willing to accept the "alternate" modifier as in the C-like formatting string.

lifthrasiir avatar Jun 27 '17 18:06 lifthrasiir

Ah, yeah # would bring it in line with std::fmt, but - brings it in line with chrono's strftime "don't include unnecessary padding" %-? operator. Definitely bikeshedable.

quodlibetor avatar Jun 27 '17 22:06 quodlibetor

That's indeed what I meant! :-)

rubdos avatar Jun 28 '17 06:06 rubdos

Relatedly, would we want some things like:

  • %-3f: format maximum of three digits stripping zeros
  • %Nf: Format arbitrary number of digits (0 - 9)
  • %-Nf: Format arbitrary number of digits, stripping zeros

quodlibetor avatar Jul 07 '17 15:07 quodlibetor