{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/29012318","id":29012318,"diff_hunk":"@@ -0,0 +1,169 @@\n+- Feature Name: Duration Reform\n+- Start Date: 2015-03-24\n+- RFC PR: (leave this empty)\n+- Rust Issue: (leave this empty)\n+\n+# Summary\n+\n+This RFC suggests stabilizing a reduced-scope `Duration` type that is appropriate for interoperating with various system calls that require timeouts. It does not stabilize a large number of conversion methods in `Duration` that have subtle caveats, with the intent of revisiting those conversions more holistically in the future.\n+\n+# Motivation\n+\n+There are a number of different notions of \"time\", each of which has a different set of caveats, and each of which can be designed for optimal ergonomics for its domain. This proposal focuses on one particular one: an amount of time in high-precision units.\n+\n+Eventually, there are a number of concepts of time that deserve fleshed out APIs. Using the terminology from the popular Java time library [JodaTime][joda-time]:\n+\n+* `Duration`: an amount of time, described in terms of a high\n+  precision unit.\n+* `Period`: an amount of time described in human terms (\"5 minutes,\n+  27 seconds\"), and which can only be resolved into a `Duration`\n+  relative to a moment in time.\n+* `Instant`: a moment in time represented in terms of a `Duration`\n+  since some epoch.\n+\n+[joda-time]: http://www.joda.org/joda-time/\n+\n+Human complications such as leap seconds, days in a month, and leap years, and machine complications such as NTP adjustments make these concepts and their full APIs more complicated than they would at first appear. This proposal focuses on fleshing out a design for `Duration` that is sufficient for use as a timeout, leaving the other concepts of time to a future proposal.\n+\n+---\n+\n+For the most part, the system APIs that this type is used to communicate with either use `timespec` (`u64` seconds plus `u32` nanos) or take a timeout in milliseconds (`u32` on Windows).\n+\n+> For example, [`GetQueuedCompletionStatus`][iocp-ms-example], one of\n+> the primary APIs in the Windows IOCP API, takes a `dwMilliseconds`\n+> parameter as a [`DWORD`][msdn-dword], which is a `u32`. Some Windows\n+> APIs use \"ticks\" or 100-nanosecond units.\n+\n+[iocp-ms-example]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364986%28v=vs.85%29.aspx\n+[msdn-dword]: https://msdn.microsoft.com/en-us/library/cc230318.aspx\n+\n+In light of that, this proposal has two primary goals:\n+\n+* to define a type that can describe portable timeouts for cross-\n+  platform APIs\n+* to describe what should happen if a large `Duration` is passed into\n+  an API that does not accept timeouts that large\n+\n+In general, this proposal considers it acceptable to reduce the granularity of timeouts (eliminating nanosecond granularity if only milliseconds are supported) and to truncate very large timeouts.\n+\n+This proposal retains the two fields in the existing `Duration`:\n+\n+* a `u64` of seconds\n+* a `u32` of additional nanosecond precision\n+\n+Timeout APIs defined in terms of milliseconds will truncate `Duration`s that are more than `u32::MAX` in milliseconds, and will reduce the granularity of the nanosecond field.\n+\n+> A `u32` of milliseconds supports a timeout longer than 45 days.\n+\n+Future APIs to support a broader set of [Durations][joda-duration] APIs, a [Period][joda-period] and [Instant][joda-instant] type, as well as coercions between these types, would be useful, compatible follow-ups to this RFC.\n+\n+[joda-duration]: http://www.joda.org/joda-time/key_duration.html\n+[joda-period]: http://www.joda.org/joda-time/key_period.html\n+[joda-instant]: http://www.joda.org/joda-time/key_instant.html\n+\n+# Detailed design\n+\n+A `Duration` represents a period of time represented in terms of nanosecond granularity. It has `u64` seconds and an additional `u32` nanoseconds. There is no concept of a negative `Duration`.\n+\n+> A negative `Duration` has no meaning for many APIs that may wish\n+> to take a `Duration`, which means that all such APIs would need\n+> to decide what to do when confronted with a negative `Duration`.\n+> As a result, this proposal focuses on the predominant use-cases for\n+> `Duration`, where unsigned types remove a number of caveats and\n+> ambiguities.\n+\n+```rust\n+pub struct Duration {\n+  secs: u64,\n+  nanos: u32 // may not be more than 1 billion\n+}\n+\n+impl Duration {\n+    /// create a Duration from a number of seconds and an\n+    /// additional nanosecond precision. If nanos is one\n+    /// billion or greater, it carries into secs.\n+    pub fn new(secs: u64, nanos: u32) -> Timeout;\n+\n+    /// create a Duration from a number of seconds\n+    pub fn from_secs(secs: u64) -> Timeout;\n+\n+    /// create a Duration from a number of milliseconds\n+    pub fn from_millis(millis: u64) -> Timeout;\n+\n+    /// the number of seconds represented by the Duration\n+    pub fn secs(self) -> u64;\n+\n+    /// the number of additional nanosecond precision\n+    pub fn nanos(self) -> u32;\n+}\n+```\n+\n+When `Duration` is used with a system API that expects `u32` milliseconds, the `Duration`'s precision is coarsened to milliseconds, and, and the number is truncated to `u32::MAX`.\n+\n+In general, this RFC assumes that timeout APIs permit spurious updates (see, for example, [pthread_cond_timedwait][pthread_cond_timedwait], \"Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur\").\n+\n+[pthread_cond_timedwait]: http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html\n+\n+`Duration` implements:\n+\n+* `Add`, `Sub`, `Mul`, `Div` which follow the overflow and underflow\n+  rules for `u64` when applied to the `secs` field (in particular,\n+  `Sub` will panic if the result would be negative). Nanoseconds\n+  must be less than 1 billion and great than or equal to 0, and carry \n+  into the `secs` field.","path":"text/0000-duration-reform.md","position":113,"original_position":113,"commit_id":"19c073ebc2563ee24561d0bd2cf17c34994e4bcb","original_commit_id":"19c073ebc2563ee24561d0bd2cf17c34994e4bcb","user":{"login":"tbu-","id":6666593,"avatar_url":"https://avatars.githubusercontent.com/u/6666593?v=3","gravatar_id":"","url":"https://api.github.com/users/tbu-","html_url":"https://github.com/tbu-","followers_url":"https://api.github.com/users/tbu-/followers","following_url":"https://api.github.com/users/tbu-/following{/other_user}","gists_url":"https://api.github.com/users/tbu-/gists{/gist_id}","starred_url":"https://api.github.com/users/tbu-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tbu-/subscriptions","organizations_url":"https://api.github.com/users/tbu-/orgs","repos_url":"https://api.github.com/users/tbu-/repos","events_url":"https://api.github.com/users/tbu-/events{/privacy}","received_events_url":"https://api.github.com/users/tbu-/received_events","type":"User","site_admin":false},"body":"Will it follow the rules of `u64` or will it also panic in non-debug mode?\r\n\r\nI'd vote for the latter, because these duration-manipulating methods are unlikely to be called in performance-sensitive code.","created_at":"2015-04-23T23:12:23Z","updated_at":"2015-04-23T23:12:23Z","html_url":"https://github.com/rust-lang/rfcs/pull/1040#discussion_r29012318","pull_request_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/29012318"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1040#discussion_r29012318"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040","id":32705936,"html_url":"https://github.com/rust-lang/rfcs/pull/1040","diff_url":"https://github.com/rust-lang/rfcs/pull/1040.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/1040.patch","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1040","number":1040,"state":"open","locked":false,"title":"Duration Reform RFC","user":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"body":"[Rendered](https://github.com/wycats/rfcs/blob/duration-reform/text/0000-duration-reform.md)","created_at":"2015-04-06T20:01:10Z","updated_at":"2015-04-23T23:12:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7ff2901aac7eec238a6feb3969c5cdbfad51866f","assignee":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1040/comments","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/19c073ebc2563ee24561d0bd2cf17c34994e4bcb","head":{"label":"wycats:duration-reform","ref":"duration-reform","sha":"19c073ebc2563ee24561d0bd2cf17c34994e4bcb","user":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"repo":{"id":29898397,"name":"rfcs","full_name":"wycats/rfcs","owner":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wycats/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/wycats/rfcs","forks_url":"https://api.github.com/repos/wycats/rfcs/forks","keys_url":"https://api.github.com/repos/wycats/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wycats/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wycats/rfcs/teams","hooks_url":"https://api.github.com/repos/wycats/rfcs/hooks","issue_events_url":"https://api.github.com/repos/wycats/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/wycats/rfcs/events","assignees_url":"https://api.github.com/repos/wycats/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/wycats/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/wycats/rfcs/tags","blobs_url":"https://api.github.com/repos/wycats/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wycats/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wycats/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/wycats/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wycats/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/wycats/rfcs/languages","stargazers_url":"https://api.github.com/repos/wycats/rfcs/stargazers","contributors_url":"https://api.github.com/repos/wycats/rfcs/contributors","subscribers_url":"https://api.github.com/repos/wycats/rfcs/subscribers","subscription_url":"https://api.github.com/repos/wycats/rfcs/subscription","commits_url":"https://api.github.com/repos/wycats/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/wycats/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/wycats/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/wycats/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/wycats/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/wycats/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wycats/rfcs/merges","archive_url":"https://api.github.com/repos/wycats/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wycats/rfcs/downloads","issues_url":"https://api.github.com/repos/wycats/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/wycats/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/wycats/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/wycats/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wycats/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/wycats/rfcs/releases{/id}","created_at":"2015-01-27T05:08:24Z","updated_at":"2015-04-06T20:45:09Z","pushed_at":"2015-04-15T03:25:07Z","git_url":"git://github.com/wycats/rfcs.git","ssh_url":"git@github.com:wycats/rfcs.git","clone_url":"https://github.com/wycats/rfcs.git","svn_url":"https://github.com/wycats/rfcs","homepage":"","size":1751,"stargazers_count":1,"watchers_count":1,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"d46a957a7605238fe91455efdb68a8534b24cdb6","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":17527989,"name":"rfcs","full_name":"rust-lang/rfcs","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rfcs","description":"RFCs for changes to Rust","fork":false,"url":"https://api.github.com/repos/rust-lang/rfcs","forks_url":"https://api.github.com/repos/rust-lang/rfcs/forks","keys_url":"https://api.github.com/repos/rust-lang/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rfcs/teams","hooks_url":"https://api.github.com/repos/rust-lang/rfcs/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rfcs/events","assignees_url":"https://api.github.com/repos/rust-lang/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rfcs/tags","blobs_url":"https://api.github.com/repos/rust-lang/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rfcs/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rfcs/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rfcs/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rfcs/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rfcs/subscription","commits_url":"https://api.github.com/repos/rust-lang/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rfcs/merges","archive_url":"https://api.github.com/repos/rust-lang/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rfcs/downloads","issues_url":"https://api.github.com/repos/rust-lang/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rfcs/releases{/id}","created_at":"2014-03-07T21:29:00Z","updated_at":"2015-04-20T21:49:10Z","pushed_at":"2015-04-23T00:56:45Z","git_url":"git://github.com/rust-lang/rfcs.git","ssh_url":"git@github.com:rust-lang/rfcs.git","clone_url":"https://github.com/rust-lang/rfcs.git","svn_url":"https://github.com/rust-lang/rfcs","homepage":"","size":11793,"stargazers_count":318,"watchers_count":318,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":191,"mirror_url":null,"open_issues_count":494,"forks":191,"open_issues":494,"watchers":318,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1040"},"issue":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1040"},"comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1040/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1040/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rfcs/statuses/19c073ebc2563ee24561d0bd2cf17c34994e4bcb"}}}}