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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f0f18f9619a04837009e623f64e2f67b263312f43fa6d4b0700f91bbd958ea5
4
- data.tar.gz: 96fa24b24f4c43448639683a9e80c9a0c90fb0a15613bf25592a8400bcb2f334
3
+ metadata.gz: 16472bce5a32a57abc8ccd393148ce0d484c45ab64613426c20345529b34e1bb
4
+ data.tar.gz: 12a94969e30573c97fb7483fee71ad21b0f4e97b58fa0588704a02c9c37b2802
5
5
  SHA512:
6
- metadata.gz: 82c32b3bf28d3cdda9ba3c07261615d7d44bf8eff66099c0d702dce3ef6eb8d3a6736e5aa560f08c8ec673756dd9ff6d8706cb136b89981c5cf2aacb9879b96a
7
- data.tar.gz: 89f5229accf3f31c703bf151eb739d75f38d51f5201b1f0f749acf102a8c167340b19493fe6f91cdcf390b9844c6f0a3cfee5455401768f6f9e9bf5af5d73db5
6
+ metadata.gz: 6b2d17fb1670ec4eb2ccc62d66ea98e075ad4a91739c7053c30c07bb89a3f0c84abf19da605ddd45760a1b854b76c9cbe89118bc22974a9265dd25f490bc3ee1
7
+ data.tar.gz: b7f22fe3958a23c76e342106eb0defd03cc63e12692d828968c6c5b67ff37149d8be6427e8d21e506c07290eb4c2994c3569fff92d443ff2d75ed5cebbc2333b
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Javan Makhmali, Basecamp
1
+ Copyright 2024 Javan Makhmali, Basecamp
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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
- 1. Add `gem 'local_time'` to your Gemfile.
8
- 2. Include `local-time.js` in your application's JavaScript bundle.
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
- //= require local-time
14
+ import LocalTime from "local-time"
15
+ LocalTime.start()
13
16
  ```
14
- Using the [local-time npm package](https://www.npmjs.com/package/local-time):
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
- ## Version History
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
- **1.0.2** (February 3, 2015)
157
+ To use this feature, configure the library to favor `data-format24` over `data-format` attributes:
163
158
 
164
- * Fix displaying future relative dates [Cezary Baginski]
165
-
166
- **1.0.1** (December 3, 2014)
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
- **0.2.0** (December 10, 2013)
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
- * Prefer `textContent` over `innerText` for Firefox compatibility
186
- * Added `options` argument to `local_time_ago` helper
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
- **0.1.0** (November 29, 2013)
169
+ This is an example of what your app configuration might look like:
189
170
 
190
- * Initial release.
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
- [![Build Status](https://travis-ci.org/basecamp/local_time.svg?branch=master)](https://travis-ci.org/basecamp/local_time)
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
- [![Sauce Test Status](https://saucelabs.com/browser-matrix/basecamp_local_time.svg)](https://saucelabs.com/u/basecamp_local_time)
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, format = extract_options_and_value(options, :format)
6
- format = find_time_format(format)
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: format
9
+ options[:data].merge! local: :time, format: format12, format24: format24
10
10
 
11
- time_tag time, time.strftime(format), options
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
- options[:format] = format || LocalTime.default_date_format
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] = 'time-ago'
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
@@ -0,0 +1,3 @@
1
+ module LocalTime
2
+ VERSION = "3.0.2"
3
+ end
@@ -1,11 +1,12 @@
1
- require 'rails'
2
- require 'action_view'
3
- require 'rails-dom-testing'
1
+ require "rails"
2
+ require "active_support/all"
3
+ require "action_view"
4
+ require "rails-dom-testing"
4
5
 
5
- require 'local_time'
6
- require_relative '../../app/helpers/local_time_helper'
6
+ require "local_time"
7
+ require_relative "../../app/helpers/local_time_helper"
7
8
 
8
- require 'minitest/autorun'
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] = '%b %e'
32
- Date::DATE_FORMATS[:date_formats_simple_date] = '%b %e'
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: '%b %e')
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, '%b %e')
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="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
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 test_local_time_with_date_formats_format
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 test_local_time_with_missing_i18n_and_date_formats_format
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: '%b %e', style: 'display:none')
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: '%b %e')
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, '%b %e')
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 test_local_date_with_date_formats_format
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 test_local_date_with_missing_i18n_and_date_formats_format
125
- expected = %Q(<time data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
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