local_time 2.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +36 -51
- data/app/assets/javascripts/local-time.es2017-esm.js +1 -0
- data/app/assets/javascripts/local-time.es2017-umd.js +1 -0
- data/app/helpers/local_time_helper.rb +72 -21
- data/lib/local_time/version.rb +3 -0
- data/test/helpers/local_time_helper_test.rb +57 -22
- data/test/javascripts/builds/index.js +24028 -0
- data/test/javascripts/fixtures/index.html +20 -0
- data/test/javascripts/fixtures/time_zone_check.html +20 -0
- data/test/javascripts/server.mjs +41 -0
- data/test/javascripts/src/format24_test.coffee +94 -0
- data/test/javascripts/src/i18n_test.coffee +2 -0
- data/test/javascripts/src/index.coffee +10 -0
- data/test/javascripts/src/local_time_test.coffee +7 -1
- data/test/javascripts/src/relative_date_test.coffee +3 -1
- data/test/javascripts/src/strftime_test.coffee +79 -0
- data/test/javascripts/src/{test.coffee → test_helpers.coffee} +8 -5
- data/test/javascripts/src/time_ago_test.coffee +2 -0
- data/test/javascripts/vendor/moment.js +5681 -2
- data/test/javascripts/vendor/sinon.js +17742 -0
- metadata +74 -21
- data/app/assets/javascripts/local-time.js +0 -1
- data/test/javascripts/fixtures/body.html +0 -8
- data/test/javascripts/vendor/sinon-timers.js +0 -385
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16472bce5a32a57abc8ccd393148ce0d484c45ab64613426c20345529b34e1bb
|
4
|
+
data.tar.gz: 12a94969e30573c97fb7483fee71ad21b0f4e97b58fa0588704a02c9c37b2802
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b2d17fb1670ec4eb2ccc62d66ea98e075ad4a91739c7053c30c07bb89a3f0c84abf19da605ddd45760a1b854b76c9cbe89118bc22974a9265dd25f490bc3ee1
|
7
|
+
data.tar.gz: b7f22fe3958a23c76e342106eb0defd03cc63e12692d828968c6c5b67ff37149d8be6427e8d21e506c07290eb4c2994c3569fff92d443ff2d75ed5cebbc2333b
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -4,14 +4,23 @@ Local Time makes it easy to display times and dates to users in their local time
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
### Importmaps
|
8
|
+
1. Add `gem "local_time"` to your Gemfile.
|
9
|
+
2. Run `bundle install`
|
10
|
+
3. Run `bin/importmap pin local-time` to add the [local-time npm package](https://www.npmjs.com/package/local-time)
|
11
|
+
4. Add this to `app/javascript/application.js`
|
9
12
|
|
10
|
-
Using the asset pipeline:
|
11
13
|
```js
|
12
|
-
|
14
|
+
import LocalTime from "local-time"
|
15
|
+
LocalTime.start()
|
13
16
|
```
|
14
|
-
|
17
|
+
|
18
|
+
### Webpacker
|
19
|
+
1. Add `gem "local_time"` to your Gemfile.
|
20
|
+
2. Run `bundle install`
|
21
|
+
3. Run `yarn add local-time`
|
22
|
+
4. Add this to `app/javascript/packs/application.js`
|
23
|
+
|
15
24
|
```js
|
16
25
|
import LocalTime from "local-time"
|
17
26
|
LocalTime.start()
|
@@ -78,7 +87,9 @@ To use a strftime format already defined in your app, pass a symbol as the forma
|
|
78
87
|
<%= local_time(date, :long) %>
|
79
88
|
```
|
80
89
|
|
81
|
-
`I18n.t("time.formats.#{format}")`, `I18n.t("date.formats.#{format}")`, `Time::DATE_FORMATS[format]`, and `Date::DATE_FORMATS[format]` will be scanned (in that order) for your format.
|
90
|
+
When using the `local_time` helper `I18n.t("time.formats.#{format}")`, `I18n.t("date.formats.#{format}")`, `Time::DATE_FORMATS[format]`, and `Date::DATE_FORMATS[format]` will be scanned (in that order) for your format.
|
91
|
+
|
92
|
+
When using the `local_date` helper, `I18n.t("date.formats.#{format}")`, `I18n.t("time.formats.#{format}")`, `Date::DATE_FORMATS[format]`, and `Time::DATE_FORMATS[format]` will be scanned (in that order) for your format.
|
82
93
|
|
83
94
|
Note: The included strftime JavaScript implementation is not 100% complete. It supports the following directives: `%a %A %b %B %c %d %e %H %I %l %m %M %p %P %S %w %y %Y %Z`
|
84
95
|
|
@@ -140,57 +151,31 @@ LocalTime.config.i18n["es"] = {
|
|
140
151
|
LocalTime.config.locale = "es"
|
141
152
|
```
|
142
153
|
|
143
|
-
|
144
|
-
|
145
|
-
**2.0.1** (June 6, 2018)
|
146
|
-
|
147
|
-
* Add `aria-label` attribute to improve accessibility
|
148
|
-
|
149
|
-
**2.0.0** (August 7, 2017)
|
150
|
-
|
151
|
-
* Add internationalization (I18n) API
|
152
|
-
* Switch to `MutationObserver` instead of listening for various DOM, Turbolinks, and jQuery events
|
153
|
-
* Publish JavaScript module on npm
|
154
|
-
* Drop coffee-rails gem dependency
|
155
|
-
* Renamed `local_time.js` to `local-time.js`
|
156
|
-
|
157
|
-
**1.0.3**
|
158
|
-
|
159
|
-
* Improve `%Z` time zone parsing
|
160
|
-
* Use [Blade](https://github.com/javan/blade) runner for JavaScript tests
|
154
|
+
**24-hour time formatting**
|
155
|
+
Local Time supports 24-hour time formats out of the box.
|
161
156
|
|
162
|
-
|
157
|
+
To use this feature, configure the library to favor `data-format24` over `data-format` attributes:
|
163
158
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
* Added `weekday-or-date` option [Chew Choon Keat]
|
169
|
-
|
170
|
-
**1.0.0** (April 12, 2014)
|
171
|
-
|
172
|
-
* Added `local_relative_time` helper with several built in types
|
173
|
-
* Allow `:format` (and `:type`) option as a bare string or value in hash
|
174
|
-
* Added `relativeDate`, `relativeTimeOrDate`, `relativeWeekday` and `run` to the API
|
175
|
-
* Dropped ineffective `popstate` event listener
|
176
|
-
* Now in use at [Basecamp](https://basecamp.com/)
|
177
|
-
|
178
|
-
**0.3.0** (February 9, 2014)
|
179
|
-
|
180
|
-
* Allow :format option lookup in I18n or DATE_FORMATS hashes [Paul Dobbins]
|
181
|
-
* Expose public API to JavaScript helpers
|
159
|
+
```js
|
160
|
+
LocalTime.config.useFormat24 = true
|
161
|
+
```
|
182
162
|
|
183
|
-
|
163
|
+
The library will now default to using the `data-format24` attribute on `<time>` elements for formatting.
|
164
|
+
But it will still fall back to `data-format` if `data-format24` is not provided.
|
184
165
|
|
185
|
-
|
186
|
-
|
166
|
+
The included Rails helpers will automatically look for 24h variants of named formats.
|
167
|
+
They will search for `#{name}_24h` in [the same places](#time-and-date-helpers) the regular name is looked up.
|
187
168
|
|
188
|
-
|
169
|
+
This is an example of what your app configuration might look like:
|
189
170
|
|
190
|
-
|
171
|
+
```ruby
|
172
|
+
Time::DATE_FORMATS[:simple] = "%-l:%M%P"
|
173
|
+
Time::DATE_FORMATS[:simple_24h] = "%H:%M"
|
174
|
+
```
|
191
175
|
|
192
|
-
|
176
|
+
When `:type` is set to `time-ago`, the format is obtained from the `I18n` [configuration](#configuration).
|
193
177
|
|
194
|
-
|
178
|
+
In practice, you might set `config.useFormat24` to `true` or `false` depending on the current user's configuration, before rendering any `<time>` elements.
|
195
179
|
|
196
|
-
|
180
|
+
## Contributing
|
181
|
+
Please read [CONTRIBUTING.md](./CONTRIBUTING.md).
|
@@ -0,0 +1 @@
|
|
1
|
+
var t;t={config:{},run:function(){return this.getController().processElements()},process:function(...t){var e,r,a;for(r=0,a=t.length;r<a;r++)e=t[r],this.getController().processElement(e);return t.length},getController:function(){return null!=this.controller?this.controller:this.controller=new t.Controller}};var e,r,a,n,s,i,o,u,l,c,d,m,h,f,g,p,S,v,y,T,b,M,D,w,E,I,C,N,A,O,$,F,Y,k,W,L=t;L.config.useFormat24=!1,L.config.i18n={en:{date:{dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbrDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbrMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],yesterday:"yesterday",today:"today",tomorrow:"tomorrow",on:"on {date}",formats:{default:"%b %e, %Y",thisYear:"%b %e"}},time:{am:"am",pm:"pm",singular:"a {time}",singularAn:"an {time}",elapsed:"{time} ago",second:"second",seconds:"seconds",minute:"minute",minutes:"minutes",hour:"hour",hours:"hours",formats:{default:"%l:%M%P",default_24h:"%H:%M"}},datetime:{at:"{date} at {time}",formats:{default:"%B %e, %Y at %l:%M%P %Z",default_24h:"%B %e, %Y at %H:%M %Z"}}}},L.config.locale="en",L.config.defaultLocale="en",L.config.timerInterval=6e4,a=!isNaN(Date.parse("2011-01-01T12:00:00-05:00")),L.parseDate=function(t){return t=t.toString(),a||(t=r(t)),new Date(Date.parse(t))},e=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/,r=function(t){var r,a,n,s,i,o,u,l,c,d;if(s=t.match(e))return[r,c,o,a,n,i,l,d]=s,"Z"!==d&&(u=d.replace(":","")),`${c}/${o}/${a} ${n}:${i}:${l} GMT${[u]}`},L.elementMatchesSelector=(n=document.documentElement,s=null!=(i=null!=(o=null!=(u=null!=(l=n.matches)?l:n.matchesSelector)?u:n.webkitMatchesSelector)?o:n.mozMatchesSelector)?i:n.msMatchesSelector,function(t,e){if((null!=t?t.nodeType:void 0)===Node.ELEMENT_NODE)return s.call(t,e)}),({config:c}=L),({i18n:m}=c),L.getI18nValue=function(t="",{locale:e}={locale:c.locale}){var r;return null!=(r=d(m[e],t))?r:e!==c.defaultLocale?L.getI18nValue(t,{locale:c.defaultLocale}):void 0},L.translate=function(t,e={},r){var a,n,s;for(a in s=L.getI18nValue(t,r),e)n=e[a],s=s.replace(`{${a}}`,n);return s},d=function(t,e){var r,a,n,s,i;for(i=t,r=0,n=(s=e.split(".")).length;r<n;r++){if(null==i[a=s[r]])return null;i=i[a]}return i},({getI18nValue:f,translate:M}=L),b="function"==typeof("undefined"!=typeof Intl&&null!==Intl?Intl.DateTimeFormat:void 0),g={"Central European Standard Time":"CET","Central European Summer Time":"CEST","China Standard Time":"CST","Israel Daylight Time":"IDT","Israel Standard Time":"IST","Moscow Standard Time":"MSK","Philippine Standard Time":"PHT","Singapore Standard Time":"SGT","Western Indonesia Time":"WIB"},L.knownEdgeCaseTimeZones=g,L.strftime=T=function(t,e){var r,a,n,s,i,o,u;return a=t.getDay(),r=t.getDate(),i=t.getMonth(),u=t.getFullYear(),n=t.getHours(),s=t.getMinutes(),o=t.getSeconds(),e.replace(/%(-?)([%aAbBcdeHIlmMpPSwyYZ])/g,(function(e,l,c){switch(c){case"%":return"%";case"a":return f("date.abbrDayNames")[a];case"A":return f("date.dayNames")[a];case"b":return f("date.abbrMonthNames")[i];case"B":return f("date.monthNames")[i];case"c":return t.toString();case"d":return p(r,l);case"e":return r;case"H":return p(n,l);case"I":return p(T(t,"%l"),l);case"l":return 0===n||12===n?12:(n+12)%12;case"m":return p(i+1,l);case"M":return p(s,l);case"p":return M("time."+(n>11?"pm":"am")).toUpperCase();case"P":return M("time."+(n>11?"pm":"am"));case"S":return p(o,l);case"w":return a;case"y":return p(u%100,l);case"Y":return u;case"Z":return S(t)}}))},p=function(t,e){return"-"===e?t:`0${t}`.slice(-2)},S=function(t){var e,r,a;return(r=h(t))?g[r]:(a=y(t,{allowGMT:!1}))||(a=v(t))?a:(e=y(t,{allowGMT:!0}))?e:""},h=function(t){return Object.keys(g).find((function(e){return b?new Date(t).toLocaleString("en-US",{timeZoneName:"long"}).includes(e):t.toString().includes(e)}))},y=function(t,{allowGMT:e}){var r;if(b&&(r=new Date(t).toLocaleString("en-US",{timeZoneName:"short"}).split(" ").pop(),e||!r.includes("GMT")))return r},v=function(t){var e,r,a,n,s;return(e=null!=(r=(s=t.toString()).match(/\(([\w\s]+)\)$/))?r[1]:void 0)?/\s/.test(e)?e.match(/\b(\w)/g).join(""):e:(e=null!=(a=s.match(/(\w{3,4})\s\d{4}$/))?a[1]:void 0)||(e=null!=(n=s.match(/(UTC[\+\-]\d+)/))?n[1]:void 0)?e:void 0},L.CalendarDate=class{static fromDate(t){return new this(t.getFullYear(),t.getMonth()+1,t.getDate())}static today(){return this.fromDate(new Date)}constructor(t,e,r){this.date=new Date(Date.UTC(t,e-1)),this.date.setUTCDate(r),this.year=this.date.getUTCFullYear(),this.month=this.date.getUTCMonth()+1,this.day=this.date.getUTCDate(),this.value=this.date.getTime()}equals(t){return(null!=t?t.value:void 0)===this.value}is(t){return this.equals(t)}isToday(){return this.is(this.constructor.today())}occursOnSameYearAs(t){return this.year===(null!=t?t.year:void 0)}occursThisYear(){return this.occursOnSameYearAs(this.constructor.today())}daysSince(t){if(t)return(this.date-t.date)/864e5}daysPassed(){return this.constructor.today().daysSince(this)}},({strftime:E,translate:I,getI18nValue:w,config:D}=L),L.RelativeTime=class{constructor(t){this.date=t,this.calendarDate=L.CalendarDate.fromDate(this.date)}toString(){var t,e;return(e=this.toTimeElapsedString())?I("time.elapsed",{time:e}):(t=this.toWeekdayString())?(e=this.toTimeString(),I("datetime.at",{date:t,time:e})):I("date.on",{date:this.toDateString()})}toTimeOrDateString(){return this.calendarDate.isToday()?this.toTimeString():this.toDateString()}toTimeElapsedString(){var t,e,r,a,n;return r=(new Date).getTime()-this.date.getTime(),a=Math.round(r/1e3),e=Math.round(a/60),t=Math.round(e/60),r<0?null:a<10?(n=I("time.second"),I("time.singular",{time:n})):a<45?`${a} ${I("time.seconds")}`:a<90?(n=I("time.minute"),I("time.singular",{time:n})):e<45?`${e} ${I("time.minutes")}`:e<90?(n=I("time.hour"),I("time.singularAn",{time:n})):t<24?`${t} ${I("time.hours")}`:""}toWeekdayString(){switch(this.calendarDate.daysPassed()){case 0:return I("date.today");case 1:return I("date.yesterday");case-1:return I("date.tomorrow");case 2:case 3:case 4:case 5:case 6:return E(this.date,"%A");default:return""}}toDateString(){var t;return t=this.calendarDate.occursThisYear()?w("date.formats.thisYear"):w("date.formats.default"),E(this.date,t)}toTimeString(){var t;return t=D.useFormat24?"default_24h":"default",E(this.date,w(`time.formats.${t}`))}},({elementMatchesSelector:C}=L),L.PageObserver=class{constructor(t,e){this.processMutations=this.processMutations.bind(this),this.processInsertion=this.processInsertion.bind(this),this.selector=t,this.callback=e}start(){if(!this.started)return this.observeWithMutationObserver()||this.observeWithMutationEvent(),this.started=!0}observeWithMutationObserver(){if("undefined"!=typeof MutationObserver&&null!==MutationObserver)return new MutationObserver(this.processMutations).observe(document.documentElement,{childList:!0,subtree:!0}),!0}observeWithMutationEvent(){return addEventListener("DOMNodeInserted",this.processInsertion,!1),!0}findSignificantElements(t){var e;return e=[],(null!=t?t.nodeType:void 0)===Node.ELEMENT_NODE&&(C(t,this.selector)&&e.push(t),e.push(...t.querySelectorAll(this.selector))),e}processMutations(t){var e,r,a,n,s,i,o,u;for(e=[],r=0,n=t.length;r<n;r++)if("childList"===(i=t[r]).type)for(a=0,s=(u=i.addedNodes).length;a<s;a++)o=u[a],e.push(...this.findSignificantElements(o));return this.notify(e)}processInsertion(t){var e;return e=this.findSignificantElements(t.target),this.notify(e)}notify(t){if(null!=t?t.length:void 0)return"function"==typeof this.callback?this.callback(t):void 0}},({parseDate:O,strftime:$,getI18nValue:A,config:N}=L),L.Controller=function(){var t,e,r,a;return t="time[data-local]:not([data-localized])",e=function(t){return t.setAttribute("data-localized","")},r=function(t){return t.setAttribute("data-processed-at",(new Date).toISOString())},a=function(t){return new L.RelativeTime(t)},class{constructor(){this.processElements=this.processElements.bind(this),this.pageObserver=new L.PageObserver(t,this.processElements)}start(){if(!this.started)return this.processElements(),this.startTimer(),this.pageObserver.start(),this.started=!0}startTimer(){var t;if(t=N.timerInterval)return null!=this.timer?this.timer:this.timer=setInterval(this.processElements,t)}processElements(e=document.querySelectorAll(t)){var r,a,n;for(a=0,n=e.length;a<n;a++)r=e[a],this.processElement(r);return e.length}processElement(t){var n,s,i,o,u,l;if(n=t.getAttribute("datetime"),i=t.getAttribute("data-local"),s=N.useFormat24&&t.getAttribute("data-format24")||t.getAttribute("data-format"),o=O(n),!isNaN(o))return t.hasAttribute("title")||(l=N.useFormat24?"default_24h":"default",u=$(o,A(`datetime.formats.${l}`)),t.setAttribute("title",u)),r(t),t.textContent=function(){switch(i){case"time":return e(t),$(o,s);case"date":return e(t),a(o).toDateString();case"time-ago":return a(o).toString();case"time-or-date":return a(o).toTimeOrDateString();case"weekday":return a(o).toWeekdayString();case"weekday-or-date":return a(o).toWeekdayString()||a(o).toDateString()}}()}}}.call(window),W=!1,F=function(){return document.attachEvent?"complete"===document.readyState:"loading"!==document.readyState},Y=function(t){var e;return null!=(e="function"==typeof requestAnimationFrame?requestAnimationFrame(t):void 0)?e:setTimeout(t,17)},k=function(){return L.getController().start()},L.start=function(){return W?L.run():(W=!0,"undefined"!=typeof MutationObserver&&null!==MutationObserver||F()?k():Y(k))},L.processing=function(){return L.getController().started},window.LocalTime===L&&L.start();export{L as default};
|
@@ -0,0 +1 @@
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).LocalTime=t()}(this,(function(){"use strict";var e;e={config:{},run:function(){return this.getController().processElements()},process:function(...e){var t,r,n;for(r=0,n=e.length;r<n;r++)t=e[r],this.getController().processElement(t);return e.length},getController:function(){return null!=this.controller?this.controller:this.controller=new e.Controller}};var t,r,n,a,i,s,o,u,l,c,d,m,h,f,g,p,y,S,v,T,b,M,D,w,E,I,C,N,A,O,$,F,Y,k,L,W=e;return W.config.useFormat24=!1,W.config.i18n={en:{date:{dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbrDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbrMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],yesterday:"yesterday",today:"today",tomorrow:"tomorrow",on:"on {date}",formats:{default:"%b %e, %Y",thisYear:"%b %e"}},time:{am:"am",pm:"pm",singular:"a {time}",singularAn:"an {time}",elapsed:"{time} ago",second:"second",seconds:"seconds",minute:"minute",minutes:"minutes",hour:"hour",hours:"hours",formats:{default:"%l:%M%P",default_24h:"%H:%M"}},datetime:{at:"{date} at {time}",formats:{default:"%B %e, %Y at %l:%M%P %Z",default_24h:"%B %e, %Y at %H:%M %Z"}}}},W.config.locale="en",W.config.defaultLocale="en",W.config.timerInterval=6e4,n=!isNaN(Date.parse("2011-01-01T12:00:00-05:00")),W.parseDate=function(e){return e=e.toString(),n||(e=r(e)),new Date(Date.parse(e))},t=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/,r=function(e){var r,n,a,i,s,o,u,l,c,d;if(i=e.match(t))return[r,c,o,n,a,s,l,d]=i,"Z"!==d&&(u=d.replace(":","")),`${c}/${o}/${n} ${a}:${s}:${l} GMT${[u]}`},W.elementMatchesSelector=(a=document.documentElement,i=null!=(s=null!=(o=null!=(u=null!=(l=a.matches)?l:a.matchesSelector)?u:a.webkitMatchesSelector)?o:a.mozMatchesSelector)?s:a.msMatchesSelector,function(e,t){if((null!=e?e.nodeType:void 0)===Node.ELEMENT_NODE)return i.call(e,t)}),({config:c}=W),({i18n:m}=c),W.getI18nValue=function(e="",{locale:t}={locale:c.locale}){var r;return null!=(r=d(m[t],e))?r:t!==c.defaultLocale?W.getI18nValue(e,{locale:c.defaultLocale}):void 0},W.translate=function(e,t={},r){var n,a,i;for(n in i=W.getI18nValue(e,r),t)a=t[n],i=i.replace(`{${n}}`,a);return i},d=function(e,t){var r,n,a,i,s;for(s=e,r=0,a=(i=t.split(".")).length;r<a;r++){if(null==s[n=i[r]])return null;s=s[n]}return s},({getI18nValue:f,translate:M}=W),b="function"==typeof("undefined"!=typeof Intl&&null!==Intl?Intl.DateTimeFormat:void 0),g={"Central European Standard Time":"CET","Central European Summer Time":"CEST","China Standard Time":"CST","Israel Daylight Time":"IDT","Israel Standard Time":"IST","Moscow Standard Time":"MSK","Philippine Standard Time":"PHT","Singapore Standard Time":"SGT","Western Indonesia Time":"WIB"},W.knownEdgeCaseTimeZones=g,W.strftime=T=function(e,t){var r,n,a,i,s,o,u;return n=e.getDay(),r=e.getDate(),s=e.getMonth(),u=e.getFullYear(),a=e.getHours(),i=e.getMinutes(),o=e.getSeconds(),t.replace(/%(-?)([%aAbBcdeHIlmMpPSwyYZ])/g,(function(t,l,c){switch(c){case"%":return"%";case"a":return f("date.abbrDayNames")[n];case"A":return f("date.dayNames")[n];case"b":return f("date.abbrMonthNames")[s];case"B":return f("date.monthNames")[s];case"c":return e.toString();case"d":return p(r,l);case"e":return r;case"H":return p(a,l);case"I":return p(T(e,"%l"),l);case"l":return 0===a||12===a?12:(a+12)%12;case"m":return p(s+1,l);case"M":return p(i,l);case"p":return M("time."+(a>11?"pm":"am")).toUpperCase();case"P":return M("time."+(a>11?"pm":"am"));case"S":return p(o,l);case"w":return n;case"y":return p(u%100,l);case"Y":return u;case"Z":return y(e)}}))},p=function(e,t){return"-"===t?e:`0${e}`.slice(-2)},y=function(e){var t,r,n;return(r=h(e))?g[r]:(n=v(e,{allowGMT:!1}))||(n=S(e))?n:(t=v(e,{allowGMT:!0}))?t:""},h=function(e){return Object.keys(g).find((function(t){return b?new Date(e).toLocaleString("en-US",{timeZoneName:"long"}).includes(t):e.toString().includes(t)}))},v=function(e,{allowGMT:t}){var r;if(b&&(r=new Date(e).toLocaleString("en-US",{timeZoneName:"short"}).split(" ").pop(),t||!r.includes("GMT")))return r},S=function(e){var t,r,n,a,i;return(t=null!=(r=(i=e.toString()).match(/\(([\w\s]+)\)$/))?r[1]:void 0)?/\s/.test(t)?t.match(/\b(\w)/g).join(""):t:(t=null!=(n=i.match(/(\w{3,4})\s\d{4}$/))?n[1]:void 0)||(t=null!=(a=i.match(/(UTC[\+\-]\d+)/))?a[1]:void 0)?t:void 0},W.CalendarDate=class{static fromDate(e){return new this(e.getFullYear(),e.getMonth()+1,e.getDate())}static today(){return this.fromDate(new Date)}constructor(e,t,r){this.date=new Date(Date.UTC(e,t-1)),this.date.setUTCDate(r),this.year=this.date.getUTCFullYear(),this.month=this.date.getUTCMonth()+1,this.day=this.date.getUTCDate(),this.value=this.date.getTime()}equals(e){return(null!=e?e.value:void 0)===this.value}is(e){return this.equals(e)}isToday(){return this.is(this.constructor.today())}occursOnSameYearAs(e){return this.year===(null!=e?e.year:void 0)}occursThisYear(){return this.occursOnSameYearAs(this.constructor.today())}daysSince(e){if(e)return(this.date-e.date)/864e5}daysPassed(){return this.constructor.today().daysSince(this)}},({strftime:E,translate:I,getI18nValue:w,config:D}=W),W.RelativeTime=class{constructor(e){this.date=e,this.calendarDate=W.CalendarDate.fromDate(this.date)}toString(){var e,t;return(t=this.toTimeElapsedString())?I("time.elapsed",{time:t}):(e=this.toWeekdayString())?(t=this.toTimeString(),I("datetime.at",{date:e,time:t})):I("date.on",{date:this.toDateString()})}toTimeOrDateString(){return this.calendarDate.isToday()?this.toTimeString():this.toDateString()}toTimeElapsedString(){var e,t,r,n,a;return r=(new Date).getTime()-this.date.getTime(),n=Math.round(r/1e3),t=Math.round(n/60),e=Math.round(t/60),r<0?null:n<10?(a=I("time.second"),I("time.singular",{time:a})):n<45?`${n} ${I("time.seconds")}`:n<90?(a=I("time.minute"),I("time.singular",{time:a})):t<45?`${t} ${I("time.minutes")}`:t<90?(a=I("time.hour"),I("time.singularAn",{time:a})):e<24?`${e} ${I("time.hours")}`:""}toWeekdayString(){switch(this.calendarDate.daysPassed()){case 0:return I("date.today");case 1:return I("date.yesterday");case-1:return I("date.tomorrow");case 2:case 3:case 4:case 5:case 6:return E(this.date,"%A");default:return""}}toDateString(){var e;return e=this.calendarDate.occursThisYear()?w("date.formats.thisYear"):w("date.formats.default"),E(this.date,e)}toTimeString(){var e;return e=D.useFormat24?"default_24h":"default",E(this.date,w(`time.formats.${e}`))}},({elementMatchesSelector:C}=W),W.PageObserver=class{constructor(e,t){this.processMutations=this.processMutations.bind(this),this.processInsertion=this.processInsertion.bind(this),this.selector=e,this.callback=t}start(){if(!this.started)return this.observeWithMutationObserver()||this.observeWithMutationEvent(),this.started=!0}observeWithMutationObserver(){if("undefined"!=typeof MutationObserver&&null!==MutationObserver)return new MutationObserver(this.processMutations).observe(document.documentElement,{childList:!0,subtree:!0}),!0}observeWithMutationEvent(){return addEventListener("DOMNodeInserted",this.processInsertion,!1),!0}findSignificantElements(e){var t;return t=[],(null!=e?e.nodeType:void 0)===Node.ELEMENT_NODE&&(C(e,this.selector)&&t.push(e),t.push(...e.querySelectorAll(this.selector))),t}processMutations(e){var t,r,n,a,i,s,o,u;for(t=[],r=0,a=e.length;r<a;r++)if("childList"===(s=e[r]).type)for(n=0,i=(u=s.addedNodes).length;n<i;n++)o=u[n],t.push(...this.findSignificantElements(o));return this.notify(t)}processInsertion(e){var t;return t=this.findSignificantElements(e.target),this.notify(t)}notify(e){if(null!=e?e.length:void 0)return"function"==typeof this.callback?this.callback(e):void 0}},({parseDate:O,strftime:$,getI18nValue:A,config:N}=W),W.Controller=function(){var e,t,r,n;return e="time[data-local]:not([data-localized])",t=function(e){return e.setAttribute("data-localized","")},r=function(e){return e.setAttribute("data-processed-at",(new Date).toISOString())},n=function(e){return new W.RelativeTime(e)},class{constructor(){this.processElements=this.processElements.bind(this),this.pageObserver=new W.PageObserver(e,this.processElements)}start(){if(!this.started)return this.processElements(),this.startTimer(),this.pageObserver.start(),this.started=!0}startTimer(){var e;if(e=N.timerInterval)return null!=this.timer?this.timer:this.timer=setInterval(this.processElements,e)}processElements(t=document.querySelectorAll(e)){var r,n,a;for(n=0,a=t.length;n<a;n++)r=t[n],this.processElement(r);return t.length}processElement(e){var a,i,s,o,u,l;if(a=e.getAttribute("datetime"),s=e.getAttribute("data-local"),i=N.useFormat24&&e.getAttribute("data-format24")||e.getAttribute("data-format"),o=O(a),!isNaN(o))return e.hasAttribute("title")||(l=N.useFormat24?"default_24h":"default",u=$(o,A(`datetime.formats.${l}`)),e.setAttribute("title",u)),r(e),e.textContent=function(){switch(s){case"time":return t(e),$(o,i);case"date":return t(e),n(o).toDateString();case"time-ago":return n(o).toString();case"time-or-date":return n(o).toTimeOrDateString();case"weekday":return n(o).toWeekdayString();case"weekday-or-date":return n(o).toWeekdayString()||n(o).toDateString()}}()}}}.call(window),L=!1,F=function(){return document.attachEvent?"complete"===document.readyState:"loading"!==document.readyState},Y=function(e){var t;return null!=(t="function"==typeof requestAnimationFrame?requestAnimationFrame(e):void 0)?t:setTimeout(e,17)},k=function(){return W.getController().start()},W.start=function(){return L?W.run():(L=!0,"undefined"!=typeof MutationObserver&&null!==MutationObserver||F()?k():Y(k))},W.processing=function(){return W.getController().started},window.LocalTime===W&&W.start(),W}));
|
@@ -2,19 +2,19 @@ module LocalTimeHelper
|
|
2
2
|
def local_time(time, options = nil)
|
3
3
|
time = utc_time(time)
|
4
4
|
|
5
|
-
options,
|
6
|
-
|
5
|
+
options, format12 = extract_options_and_value(options, :format)
|
6
|
+
format12, format24 = find_12h_and_24h_formats(format12)
|
7
7
|
|
8
8
|
options[:data] ||= {}
|
9
|
-
options[:data].merge! local: :time, format:
|
9
|
+
options[:data].merge! local: :time, format: format12, format24: format24
|
10
10
|
|
11
|
-
time_tag time, time.strftime(
|
11
|
+
time_tag time, time.strftime(format12), options
|
12
12
|
end
|
13
13
|
|
14
14
|
def local_date(time, options = nil)
|
15
15
|
options, format = extract_options_and_value(options, :format)
|
16
|
-
|
17
|
-
local_time time, options
|
16
|
+
format, _ = find_12h_and_24h_formats(format, prefer: :date)
|
17
|
+
local_time time, options.merge(format: format)
|
18
18
|
end
|
19
19
|
|
20
20
|
def local_relative_time(time, options = nil)
|
@@ -29,7 +29,7 @@ module LocalTimeHelper
|
|
29
29
|
|
30
30
|
def local_time_ago(time, options = nil)
|
31
31
|
options, * = extract_options_and_value(options, :type)
|
32
|
-
options[:type] =
|
32
|
+
options[:type] = "time-ago"
|
33
33
|
local_relative_time time, options
|
34
34
|
end
|
35
35
|
|
@@ -42,20 +42,6 @@ module LocalTimeHelper
|
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
|
-
def find_time_format(format)
|
46
|
-
if format.is_a?(Symbol)
|
47
|
-
if (i18n_format = I18n.t("time.formats.#{format}", default: [:"date.formats.#{format}", ''])).present?
|
48
|
-
i18n_format
|
49
|
-
elsif (date_format = Time::DATE_FORMATS[format] || Date::DATE_FORMATS[format])
|
50
|
-
date_format.is_a?(Proc) ? LocalTime.default_time_format : date_format
|
51
|
-
else
|
52
|
-
LocalTime.default_time_format
|
53
|
-
end
|
54
|
-
else
|
55
|
-
format.presence || LocalTime.default_time_format
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
45
|
def extract_options_and_value(options, value_key = nil)
|
60
46
|
case options
|
61
47
|
when Hash
|
@@ -67,4 +53,69 @@ module LocalTimeHelper
|
|
67
53
|
[ {}, options ]
|
68
54
|
end
|
69
55
|
end
|
56
|
+
|
57
|
+
def find_12h_and_24h_formats(format12, prefer: :time)
|
58
|
+
if format12.is_a?(Symbol)
|
59
|
+
find_time_formats_by_name(format12, prefer: prefer)
|
60
|
+
else
|
61
|
+
[ format12.presence || default_time_format(prefer), nil ]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_time_formats_by_name(name, prefer:)
|
66
|
+
if use_i18n_time_formats?(name)
|
67
|
+
find_i18_time_formats(name, prefer: prefer)
|
68
|
+
elsif use_ruby_time_formats?(name)
|
69
|
+
find_ruby_time_formats(name, prefer: prefer)
|
70
|
+
else
|
71
|
+
[ default_time_format(prefer), nil ]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def default_time_format(prefer = :time)
|
76
|
+
if prefer == :time
|
77
|
+
LocalTime.default_time_format
|
78
|
+
else
|
79
|
+
LocalTime.default_date_format
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def use_i18n_time_formats?(name)
|
84
|
+
i18n_time_or_date_format(name).present?
|
85
|
+
end
|
86
|
+
|
87
|
+
def i18n_time_or_date_format(name, prefer: :time)
|
88
|
+
if prefer == :time
|
89
|
+
I18n.t("time.formats.#{name}", default: [ :"date.formats.#{name}", "" ]).presence
|
90
|
+
else
|
91
|
+
I18n.t("date.formats.#{name}", default: [ :"time.formats.#{name}", "" ]).presence
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_i18_time_formats(name, prefer:)
|
96
|
+
[ i18n_time_or_date_format(name, prefer: prefer),
|
97
|
+
i18n_time_or_date_format("#{name}_24h", prefer: prefer) ]
|
98
|
+
end
|
99
|
+
|
100
|
+
def use_ruby_time_formats?(name)
|
101
|
+
ruby_time_or_date_format(name).present?
|
102
|
+
end
|
103
|
+
|
104
|
+
def ruby_time_or_date_format(name, prefer: :time)
|
105
|
+
if prefer == :time
|
106
|
+
Time::DATE_FORMATS.with_indifferent_access[name] || Date::DATE_FORMATS.with_indifferent_access[name]
|
107
|
+
else
|
108
|
+
Date::DATE_FORMATS.with_indifferent_access[name] || Time::DATE_FORMATS.with_indifferent_access[name]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_ruby_time_formats(name, prefer:)
|
113
|
+
format12 = ruby_time_or_date_format(name, prefer: prefer)
|
114
|
+
|
115
|
+
if format12.is_a?(Proc)
|
116
|
+
[ default_time_format(prefer), nil ]
|
117
|
+
else
|
118
|
+
[ format12, ruby_time_or_date_format("#{name}_24h", prefer: prefer) ]
|
119
|
+
end
|
120
|
+
end
|
70
121
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "rails"
|
2
|
+
require "active_support/all"
|
3
|
+
require "action_view"
|
4
|
+
require "rails-dom-testing"
|
4
5
|
|
5
|
-
require
|
6
|
-
require_relative
|
6
|
+
require "local_time"
|
7
|
+
require_relative "../../app/helpers/local_time_helper"
|
7
8
|
|
8
|
-
require
|
9
|
+
require "minitest/autorun"
|
9
10
|
begin
|
10
11
|
# 2.0.0
|
11
12
|
class TestCase < MiniTest::Test; end
|
@@ -26,10 +27,14 @@ class LocalTimeHelperTest < TestCase
|
|
26
27
|
@original_zone = Time.zone
|
27
28
|
Time.zone = ActiveSupport::TimeZone["Central Time (US & Canada)"]
|
28
29
|
I18n.backend.store_translations(:en, {
|
29
|
-
time: { formats: { simple_time: "%b %e" } },
|
30
|
-
date: { formats: { simple_date: "%b %e" } } })
|
31
|
-
Time::DATE_FORMATS[:time_formats_simple_time] =
|
32
|
-
|
30
|
+
time: { formats: { simple_time: "%-l:%M%P", simple_time_24h: "%H:%M", time_with_context: "%b %e, %-l:%M%P", ambiguous_format: "%Y-%m-%d %H:%M:%S" } },
|
31
|
+
date: { formats: { simple_date: "%b %e", ambiguous_format: "%Y-%m-%d" } } })
|
32
|
+
Time::DATE_FORMATS[:time_formats_simple_time] = "%-l:%M%P"
|
33
|
+
Time::DATE_FORMATS[:time_formats_simple_time_24h] = "%H:%M"
|
34
|
+
Time::DATE_FORMATS[:time_formats_time_with_context] = "%b %e, %-l:%M%P"
|
35
|
+
Time::DATE_FORMATS[:ruby_ambiguous_format] = "%Y-%m-%d %H:%M:%S"
|
36
|
+
Date::DATE_FORMATS[:ruby_ambiguous_format] = "%Y-%m-%d"
|
37
|
+
Date::DATE_FORMATS[:date_formats_simple_date] = "%b %e"
|
33
38
|
|
34
39
|
@date = "2013-11-21"
|
35
40
|
@time = Time.zone.parse(@date)
|
@@ -61,25 +66,35 @@ class LocalTimeHelperTest < TestCase
|
|
61
66
|
|
62
67
|
def test_local_time_with_format
|
63
68
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
64
|
-
assert_dom_equal expected, local_time(@time, format:
|
69
|
+
assert_dom_equal expected, local_time(@time, format: "%b %e")
|
65
70
|
end
|
66
71
|
|
67
72
|
def test_local_time_with_format_as_string
|
68
73
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
69
|
-
assert_dom_equal expected, local_time(@time,
|
74
|
+
assert_dom_equal expected, local_time(@time, "%b %e")
|
70
75
|
end
|
71
76
|
|
72
77
|
def test_local_time_with_i18n_format
|
73
|
-
expected = %Q(<time data-format="%
|
78
|
+
expected = %Q(<time data-format="%-l:%M%P" data-format24="%H:%M" data-local="time" datetime="#{@time_js}">6:00am</time>)
|
74
79
|
assert_dom_equal expected, local_time(@time, format: :simple_time)
|
75
80
|
end
|
76
81
|
|
77
|
-
def
|
78
|
-
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
82
|
+
def test_local_time_with_i18n_format_missing_24h
|
83
|
+
expected = %Q(<time data-format="%b %e, %-l:%M%P" data-local="time" datetime="#{@time_js}">Nov 21, 6:00am</time>)
|
84
|
+
assert_dom_equal expected, local_time(@time, format: :time_with_context)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_local_time_with_ruby_format
|
88
|
+
expected = %Q(<time data-format="%-l:%M%P" data-format24="%H:%M" data-local="time" datetime="#{@time_js}">6:00am</time>)
|
79
89
|
assert_dom_equal expected, local_time(@time, format: :time_formats_simple_time)
|
80
90
|
end
|
81
91
|
|
82
|
-
def
|
92
|
+
def test_local_time_with_ruby_format_missing_24h
|
93
|
+
expected = %Q(<time data-format="%b %e, %-l:%M%P" data-local="time" datetime="#{@time_js}">Nov 21, 6:00am</time>)
|
94
|
+
assert_dom_equal expected, local_time(@time, format: :time_formats_time_with_context)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_local_time_with_missing_i18n_and_ruby_format
|
83
98
|
expected = %Q(<time data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
84
99
|
assert_dom_equal expected, local_time(@time, format: :missing_format)
|
85
100
|
end
|
@@ -92,7 +107,27 @@ class LocalTimeHelperTest < TestCase
|
|
92
107
|
|
93
108
|
def test_local_time_with_options
|
94
109
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}" style="display:none">Nov 21</time>)
|
95
|
-
assert_dom_equal expected, local_time(@time, format:
|
110
|
+
assert_dom_equal expected, local_time(@time, format: "%b %e", style: "display:none")
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_local_time_with_ruby_ambiguous_format
|
114
|
+
expected = %Q(<time data-format="%Y-%m-%d %H:%M:%S" data-local="time" datetime="#{@time_js}">2013-11-21 06:00:00</time>)
|
115
|
+
assert_dom_equal expected, local_time(@time, format: :ruby_ambiguous_format)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_local_time_with_i18n_ambiguous_format
|
119
|
+
expected = %Q(<time data-format="%Y-%m-%d %H:%M:%S" data-local="time" datetime="#{@time_js}">2013-11-21 06:00:00</time>)
|
120
|
+
assert_dom_equal expected, local_time(@time, format: :ambiguous_format)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_local_date_with_ruby_ambiguous_format
|
124
|
+
expected = %Q(<time data-format="%Y-%m-%d" data-local="time" datetime="#{@time_js}">2013-11-21</time>)
|
125
|
+
assert_dom_equal expected, local_date(@time.to_date, format: :ruby_ambiguous_format)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_local_date_with_i18n_ambiguous_format
|
129
|
+
expected = %Q(<time data-format="%Y-%m-%d" data-local="time" datetime="#{@time_js}">2013-11-21</time>)
|
130
|
+
assert_dom_equal expected, local_date(@time.to_date, format: :ambiguous_format)
|
96
131
|
end
|
97
132
|
|
98
133
|
def test_local_date
|
@@ -103,12 +138,12 @@ class LocalTimeHelperTest < TestCase
|
|
103
138
|
|
104
139
|
def test_local_date_with_format
|
105
140
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
106
|
-
assert_dom_equal expected, local_date(@time.to_date, format:
|
141
|
+
assert_dom_equal expected, local_date(@time.to_date, format: "%b %e")
|
107
142
|
end
|
108
143
|
|
109
144
|
def test_local_date_with_format_as_string
|
110
145
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
111
|
-
assert_dom_equal expected, local_date(@time.to_date,
|
146
|
+
assert_dom_equal expected, local_date(@time.to_date, "%b %e")
|
112
147
|
end
|
113
148
|
|
114
149
|
def test_local_date_with_i18n_format
|
@@ -116,13 +151,13 @@ class LocalTimeHelperTest < TestCase
|
|
116
151
|
assert_dom_equal expected, local_date(@time.to_date, format: :simple_date)
|
117
152
|
end
|
118
153
|
|
119
|
-
def
|
154
|
+
def test_local_date_with_ruby_format
|
120
155
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
121
156
|
assert_dom_equal expected, local_date(@time.to_date, format: :date_formats_simple_date)
|
122
157
|
end
|
123
158
|
|
124
|
-
def
|
125
|
-
expected = %Q(<time data-format="%B %e, %Y
|
159
|
+
def test_local_date_with_missing_i18n_and_ruby_format
|
160
|
+
expected = %Q(<time data-format="%B %e, %Y" data-local="time" datetime="#{@time_js}">November 21, 2013</time>)
|
126
161
|
assert_dom_equal expected, local_date(@time.to_date, format: :missing_date_format)
|
127
162
|
end
|
128
163
|
|