Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] ApproximateCreationDateTime from DynamoDBStreamRecord in milliseconds when originating from Kinesis, not seconds. #478

Open
seanlane opened this issue Jan 4, 2023 · 2 comments
Labels
type/events issue or feature request related to the events package

Comments

@seanlane
Copy link

seanlane commented Jan 4, 2023

This is essentially the same issue as aws/aws-lambda-dotnet#839, but without crashing deserialization, which I'm guessing is due to the use of float64 that avoids overflowing with the larger value to deserialize. The relevant points of discussion are:

It seems that the value of ApproximateCreationDateTime will be in seconds when coming from a DynamoDB Stream, but in milliseconds when coming from a Kinesis Stream:

The approximate date and time when the stream record was created, in UNIX epoch time format and rounded down to the closest second

ApproximateCreationDateTime indicates the time of the modification in milliseconds.

There appears to be an internal ticket that's being tracked, so I wanted to open an issue here as well for AWS to monitor and hopefully resolve in the near future. Thanks!

@seanlane
Copy link
Author

seanlane commented Jan 4, 2023

It may not crash, but Unmarshaling and Marshaling a value will cause an overflow for most Unix timestamps due to calling time.UnixNano, toy example:

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

// SecondsEpochTime serializes a time.Time in JSON as a UNIX epoch time in seconds
type SecondsEpochTime struct {
	time.Time
}

const secondsToNanoSecondsFactor = 1000000000
const milliSecondsToNanoSecondsFactor = 1000000

func TestUnmarshalJSON(epoch float64) time.Time {
	epochSec := int64(epoch)
	epochNano := int64((epoch - float64(epochSec)) * float64(secondsToNanoSecondsFactor))
	return time.Unix(epochSec, epochNano)
}

func TestMarshalJSON(t time.Time) ([]byte, error) {
	// UnixNano() returns the epoch in nanoseconds
	unixTime := float64(t.UnixNano()) / float64(secondsToNanoSecondsFactor)
	return json.Marshal(unixTime)
}

func testVal(test float64) time.Time {
	convertedTime := TestUnmarshalJSON(test)
	convertBack, _ := TestMarshalJSON(convertedTime)
	fmt.Printf("%f\t%s\t%s\n", test, convertedTime.String(), convertBack)
	return convertedTime
}

func main() {
	testVal(1669739327580.0) // Millisecond
	testVal(1669739327.0)    // Second
}
1669739327580.000000	54881-12-06 15:53:00 +0000 UTC	-8914383127.569197
1669739327.000000	2022-11-29 16:28:47 +0000 UTC	1669739327

@bmoffatt
Copy link
Collaborator

aws/aws-lambda-dotnet#839 (comment) claims that this only occurs when the dynamo event is first passed through kinesis. Do I understand that correctly? If so, I'm not sure if this is something that's supportable, and the function should operate on the Kinesis event rather than the Dynamo event

@bmoffatt bmoffatt added the type/events issue or feature request related to the events package label Apr 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/events issue or feature request related to the events package
Projects
None yet
Development

No branches or pull requests

2 participants