/* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
                                         const uint8_t *der, uint8_t *der_end)
{
    int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
    if (!SecAbsoluteTimeGetGregorianDate(at, &year, &month, &day, &hour, &minute, &second, error))
        return NULL;

    return ccder_encode_decimal_quad(year, der,
           ccder_encode_decimal_pair(month, der,
           ccder_encode_decimal_pair(day, der,
           ccder_encode_decimal_pair(hour, der,
           ccder_encode_decimal_pair(minute, der,
           ccder_encode_decimal_pair(second, der,
           ccder_encode_nanoseconds(at, der,
           ccder_encode_byte('Z', der, der_end))))))));
}
/* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
                                         const uint8_t *der, uint8_t *der_end)
{
    CFGregorianDate g = SecCFAbsoluteTimeGetGregorianDate(floor(at), 0.0, error);
    if (g.year == 0)
        return NULL;

    return ccder_encode_decimal_quad(g.year, der,
           ccder_encode_decimal_pair(g.month, der,
           ccder_encode_decimal_pair(g.day, der,
           ccder_encode_decimal_pair(g.hour, der,
           ccder_encode_decimal_pair(g.minute, der,
           ccder_encode_decimal_pair(g.second, der,
           ccder_encode_nanoseconds(at, der,
           ccder_encode_byte('Z', der, der_end))))))));
}