Skip to content

Preserve sub-second precision when serializing timestamps - #3353

Open
jonathan343 wants to merge 1 commit into
aws:masterfrom
jonathan343:preserve-subsecond-timestamps
Open

jonathan343 wants to merge 1 commit into
aws:masterfrom
jonathan343:preserve-subsecond-timestamps

Conversation

@jonathan343

Copy link
Copy Markdown
Contributor

Overview

The PHP SDK serializes request timestamps by calling DateTimeInterface::getTimestamp() (or strtotime() for strings), which returns whole seconds and drops any sub-second precision the caller provided. This affects the unixTimestamp format used by json, rest-json, and smithy-rpc-v2-cbor bodies, and the iso8601 format used by query, rest-xml, and REST querystring/URI bindings. rfc822 (HTTP-date) only supports whole seconds and is unchanged.

This PR preserves the caller's sub-second precision for unixTimestamp and iso8601. Whole-second timestamps serialize exactly as before. It is the PHP counterpart to boto/botocore#3796 and fixes the PHP equivalent of boto/botocore#3255.

Testing

Added unit tests for TimestampShape::format() / formatAsString() and end-to-end serializer tests for json, query, rest-xml, and rest-json bindings. Protocol compliance tests pass. PHPStan reports no errors on the touched files.

Reproduced the scenario from boto/botocore#3255 with KinesisVideoArchivedMedia::listFragments, capturing the serialized body with a mock handler:

<?php
require 'vendor/autoload.php';

use Aws\KinesisVideoArchivedMedia\KinesisVideoArchivedMediaClient;
use Aws\Result;
use GuzzleHttp\Promise\Create;

$client = new KinesisVideoArchivedMediaClient([
    'region' => 'us-east-1',
    'version' => 'latest',
    'credentials' => ['key' => 'AKID', 'secret' => 'SECRET'],
    // Capture the serialized request instead of sending it.
    'handler' => function ($command, $request) {
        echo "POST {$request->getUri()->getPath()}\n";
        echo "body: {$request->getBody()}\n";
        return Create::promiseFor(new Result(['Fragments' => []]));
    },
]);

$client->listFragments([
    'StreamName' => 'some-stream',
    'FragmentSelector' => [
        'FragmentSelectorType' => 'PRODUCER_TIMESTAMP',
        'TimestampRange' => [
            'StartTimestamp' => new DateTimeImmutable('2024-09-12T10:49:36.500000+00:00'),
            'EndTimestamp'   => new DateTimeImmutable('2024-09-12T10:49:38.833000+00:00'),
        ],
    ],
]);

Before (master):

POST /listFragments
body: {"StreamName":"some-stream","FragmentSelector":{"FragmentSelectorType":"PRODUCER_TIMESTAMP","TimestampRange":{"StartTimestamp":1726138176,"EndTimestamp":1726138178}}}

After:

POST /listFragments
body: {"StreamName":"some-stream","FragmentSelector":{"FragmentSelectorType":"PRODUCER_TIMESTAMP","TimestampRange":{"StartTimestamp":1726138176.5,"EndTimestamp":1726138178.833}}}

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Serialize unixTimestamp and iso8601 request timestamps with the
sub-second precision the caller provided instead of truncating to
whole seconds. Whole-second values are unchanged; rfc822 remains
whole seconds per spec.

Add TimestampShape::formatAsString for string-bound locations
(query, XML, REST headers/querystring/URI) so float epoch values are
not truncated by PHP's `precision` ini setting when cast to string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant