daegalus / dart-uuid

Generate RFC9562(v1,v4,v5,v6,v7,v8) UUIDs
MIT License
360 stars 77 forks source link

About the time of UUIDv1 generation #119

Closed bymoye closed 4 months ago

bymoye commented 4 months ago

code:

import 'package:uuid/uuid.dart';

void main() {
  print(DateTime.now());
  final uuid = Uuid();
  final uuidv1 = uuid.v1();
  print("uuidv1: $uuidv1");

  final uuid1String = uuidv1.replaceAll("-", "");
  final uuid1Int = BigInt.parse(uuid1String, radix: 16);
  final timeLow = uuid1Int >> 96;
  final timeMid = (uuid1Int >> 80) & BigInt.from(0xffff);
  final timeHiVersion = (uuid1Int >> 64) & BigInt.from(0xffff);

  final time = (((timeHiVersion & BigInt.from(0x0fff)) << 48) |
      (timeMid << 32) |
      timeLow);

  print(time);

  print(DateTime(1582, 10, 15).add(Duration(microseconds: time.toInt() ~/ 10)));
}

output:

2024-07-08 15:35:23.406210
uuidv1: 3167ac30-dc12-1073-b875-09a213f70510
32611593018125360
1686-02-15 21:35:01.812536

I tried to generate a uuidv1 in python, and the time parsed by the code is normal. However, the time of the uuidv1 generated in our library is abnormal. Why is this happening?

I also used uuidtools, also with the same result.

bymoye commented 4 months ago

if change file: lib/v1.dart middle int mSecs = options?.mSecs ?? DateTime.timestamp().microsecondsSinceEpoch to int mSecs = options?.mSecs ?? DateTime.timestamp().millisecondsSinceEpoch then everything will work fine. output:

2024-07-08 20:01:32.281814
uuidv1: d1162800-3d21-11ef-9494-3dd2a7fe7cd7
139397328922880000
2024-07-08 12:01:32.288

and uuidtools image

bymoye commented 4 months ago

https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-1

daegalus commented 4 months ago

Because Javascript does not have millisecond precision for time due to limitations of integers in JS (they are only 53bits, a long is 64bits, which is what dart uses for millisecondsFromEpoch). And this library needs to work in DartJS and other targets. It used to be milliseconds until I got bug reports to the contrary.

I use the alternative method of NodeID + ClockSeq to deal with that, which is part of the spec.

bymoye commented 4 months ago

Because Javascript does not have millisecond precision for time due to limitations of integers in JS (they are only 53bits, a long is 64bits, which is what dart uses for millisecondsFromEpoch). And this library needs to work in DartJS and other targets. It used to be milliseconds until I got bug reports to the contrary.

I use the alternative method of NodeID + ClockSeq to deal with that, which is part of the spec.

I tried changing the microsecondsSinceEpoch in the code to millisecondsSinceEpoch, and then running it in chrome v125 using flutter web and the results I saw were the same. Maybe we only need to change the microsecondsSinceEpoch in the code to millisecondsSinceEpoch to solve the problem? The purpose is to fix the problem of incorrect timestamp value in the uuid generated by this library UUIDv1.

daegalus commented 4 months ago

Ok, maybe the issue was fixed. I will make the change and make sure all my tests are passing and verify some other stuff.

bymoye commented 4 months ago

Ok, maybe the issue was fixed. I will make the change and make sure all my tests are passing and verify some other stuff.

ok~thx

daegalus commented 4 months ago

Thank you for catching this. It seems this was an error on my part when I was refactoring/rebasing the version 4 release. It should have been millisecondsSinceEpoch, just like UUIDv6, but somehow got changed to microseconds.

I have added a test to catch this in the future.

v4.4.1 is pushed, that includes the fix.