Home > Back-end >  What does NNN mean in date format <YYMMDDhhmmssNNN><C|D|G|H>?
What does NNN mean in date format <YYMMDDhhmmssNNN><C|D|G|H>?

Time:11-12

hi I has date format and I want converted to correct GMT date :

<YYMMDDhhmmssNNN><C|D|G|H>

Sample value on that date: 210204215026000C

I get this explanation for part NNN :

NNN     If flag is C or D then NNN is the number of hours relativeto GMT,
        if flag is G or H, NNN is the number of quarter hours relative to GMT
C|D|G|H C and G = Ahead of GMT, D and H = Behind GMT

but I did not get how number of hours relative to GMT can present on 3 digits ? it should be in 2 digit as i knew the offset for hours related to GMT is from 0 to 23 , and also what quarter hours relative to GMT mean ?

I want to use Scala or Java.

CodePudding user response:

I don’t know why they set 3 digits aside for the offset. I agree with you that 2 digits suffice for all cases. Maybe they just wanted to be very sure they would never run of out space, and maybe they even overdid this a bit. 3 digits is not a problem as long as the actual values are within the range that java.time.ZoneOffset can handle, /-18 hours. In your example NNN is 000, so 0 hours from GMT, which certainly is OK and trivial to handle.

A quarter hour is a quarter of an hour. As Salman A mentioned in a comment, 22 quarter hours ahead of Greenwich means an offset of 05:30, currently used in Sri Lanka and India. If the producer of the string wants to use this option, they can give numbers up to 72 (still comfortably within 2 digits). 18 * 4 = 72, so 18 hours equals 72 quarter hours. To imagine a situation where 2 digits would be too little, think an offset of 25 hours. I wouldn’t think it realistic, on the other hand no one can guarantee that it will never happen.

Java solution: how to parse and convert to GMT time

I am using these constants:

private static final Pattern DATE_PATTERN
        = Pattern.compile("(\\d{12})(\\d{3})(\\w)");
private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("uuMMddHHmmss");
private static final int SECONDS_IN_A_QUARTER_HOUR
        = Math.toIntExact(Duration.ofHours(1).dividedBy(4).getSeconds());

Parse and convert like this:

    String sampleValue = "210204215026000C";
    Matcher matcher = DATE_PATTERN.matcher(sampleValue);
    if (matcher.matches()) {
        LocalDateTime ldt = LocalDateTime.parse(matcher.group(1), FORMATTER);
        int offsetAmount = Integer.parseInt(matcher.group(2));
        char flag = matcher.group(3).charAt(0);

        // offset amount denotes either hours or quarter hours
        boolean quarterHours = flag == 'G' || flag == 'H';
        boolean negative = flag == 'D' || flag == 'H';
        if (negative) {
            offsetAmount = -offsetAmount;
        }
        ZoneOffset offset = quarterHours
                ? ZoneOffset.ofTotalSeconds(offsetAmount * SECONDS_IN_A_QUARTER_HOUR)
                : ZoneOffset.ofHours(offsetAmount);

        OffsetDateTime dateTime = ldt.atOffset(offset);
        OffsetDateTime gmtDateTime = dateTime.withOffsetSameInstant(ZoneOffset.UTC);

        System.out.println("GMT time: "   gmtDateTime);
    }
    else {
        System.out.println("Invalid value: "   sampleValue);
    }

Output is:

GMT time: 2021-02-04T21:50:26Z

I think my code covers all valid cases. You will probably want to validate that the flag is indeed C, D, G or H, and also handle the potential DateTimeException and NumberFormatException from the parsing and creating the ZoneOffset (NumberFormatException should not happen).

  • Related