OpenZeppelin / openzeppelin-contracts

OpenZeppelin Contracts is a library for secure smart contract development.
https://openzeppelin.com/contracts
MIT License
24.83k stars 11.78k forks source link

DateTimeUtils - Helper logic to handle time #1531

Open rmeissner opened 5 years ago

rmeissner commented 5 years ago

🧐 Motivation Time is important and off-chain there are often cases where time related checks need to be performed. To handle this on chain it would be nice to have some utils that would encapsulate these checks.

There are many use cases for this:

📝 Details There is a library that is already implementing this logic (https://github.com/pipermerriam/ethereum-datetime), but this is not really up to date, nor audited.

Also it would be interesting to consider edge cases like leap seconds (at least mention why they are not implemented).

An api should include method to check if what year/ month/ day/ hour/ minute a certain timestamp is.

nventuro commented 5 years ago

A point we'll have to address if attempting to cater to a 'calendar day' usage will be that of timezones, which may be a major issue due to daylight savings, etc.

rmeissner commented 5 years ago

Yes that is true. I would probably assume UTC for simplicity and it would be possible to shift the time (e.g UTC+1 or UTC-10)

frangio commented 5 years ago

Leap seconds are dealt with at the EVM level. The unix timestamp that is obtained from block.timestamp doesn't count real seconds, it counts "civil" seconds. Notice in this table how the same timestamp ending in 800 actually spans two real seconds.

nventuro commented 5 years ago

In https://github.com/OpenZeppelin/openzeppelin-solidity/issues/533, the case was made for extending this to also include support for a cleaner Date type. According to Solidity developers here, this should be done by us, not the language.

alcuadrado commented 5 years ago

533 is quite old, and there's some discussion in that issue related to the security/correctness of using block.timestamp. I think that discussion is not relevant anymore, but the original proposal by @martriay is still relevant.

There's some ambiguity in #533, as it is not clear if it proposes Date to be a function or a type because of the capital D. I think it was intended to be a function, which IMO would be a great starting point.

alcuadrado commented 5 years ago

The reason I commented on this issue is that while auditing a smart contract I found errors in the way dates were computed.

The contract I was auditing had to lock some tokens until a certain date. It computed dates with now + offset. This has two problems: (1) it depends on the deployment date. (2) the offset is easy to get wrong (spoiler: it was wrong).

I'd love to recommend the authors to use a human-readable representation of the dates, but I couldn't find a maintained function/lib for doing so. Having something like dateToTimestamp(year, month, day) would be enough for this use-case.

frangio commented 5 years ago

So, functions to create timestamps from human dates: date(2019, 06, 12), datetime(2019, 06, 12, 00, 00). Sounds quite reasonable and useful.

Would these functions return the uint256 timestamp directly, or a struct with operations?

Also, how should we deal with timezones?


(2) the offset is easy to get wrong (spoiler: it was wrong).

@alcuadrado Mind sharing how it was wrong exactly?

nventuro commented 5 years ago

Timezones are a mess, and DST only complicates matters further. I'd make it so that times specified in either UTC, or at a fixed offset (e.g. UTC+8 for Hong Kong, UTC-4 for Chile, etc.).

alcuadrado commented 5 years ago

Would these functions return the uint256 timestamp directly, or a struct with operations?

I think functions would be more efficient.

Btw, some of the functions in this library are also super useful.

Also, how should we deal with timezones?

I'd only do UTC. I don't see a way of managing timezones trustlessly, as any government can change their country's timezone whenever they want.

@alcuadrado Mind sharing how it was wrong exactly?

The offset was expressed as <base> * <units multiplier>, and the <unit multiplier> was wrong. Still, if it weren't wrong, reading it is way harder than a normal date (i.e. year, month & day).

princesinha19 commented 4 years ago

@nventuro @frangio Guys, Any progress on this issue?

frangio commented 4 years ago

We're interested in adding this to the library. No one has started working on it yet.

This looks like good information for whoever wants to work on this: Low-Level Date Algorithms

pasevin commented 3 years ago

Is this even under consideration?

frangio commented 3 years ago

The team is not proactively working on this feature but we would be happy to receive a PR implementing the interface I described above:

functions to create timestamps from human dates: date(2019, 06, 12), datetime(2019, 06, 12, 00, 00)