playbook_ui 12.37.0.pre.alpha.svgiconmethods1064 → 12.38.0.pre.alpha.PLAY932removemomentqp1088

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_date/_date.tsx +7 -8
  3. data/app/pb_kits/playbook/pb_date/docs/_date_alignment.jsx +2 -2
  4. data/app/pb_kits/playbook/pb_date/docs/_date_default.jsx +29 -5
  5. data/app/pb_kits/playbook/pb_date/docs/_date_unstyled.jsx +2 -2
  6. data/app/pb_kits/playbook/pb_date/docs/_date_variants.jsx +5 -5
  7. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +18 -8
  8. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +45 -39
  9. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +45 -31
  10. data/app/pb_kits/playbook/pb_date_range_stacked/_date_range_stacked.tsx +5 -3
  11. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +24 -21
  12. data/app/pb_kits/playbook/pb_date_time/_date_time.tsx +1 -1
  13. data/app/pb_kits/playbook/pb_date_time/dateTime.test.js +1 -1
  14. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +2 -2
  15. data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.test.js +1 -1
  16. data/app/pb_kits/playbook/pb_date_year_stacked/_date_year_stacked.tsx +6 -8
  17. data/app/pb_kits/playbook/pb_icon/docs/_icon_animate.html.erb +0 -1
  18. data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.html.erb +0 -2
  19. data/app/pb_kits/playbook/pb_icon/docs/example.yml +9 -10
  20. data/app/pb_kits/playbook/pb_icon/icon.html.erb +3 -3
  21. data/app/pb_kits/playbook/pb_icon/icon.rb +0 -19
  22. data/app/pb_kits/playbook/pb_kit/dateTime.ts +347 -61
  23. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +52 -31
  24. data/app/pb_kits/playbook/pb_message/_message.tsx +24 -24
  25. data/app/pb_kits/playbook/pb_time/_time.tsx +9 -11
  26. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +46 -49
  27. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.tsx +4 -6
  28. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +11 -11
  29. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +8 -11
  30. data/dist/playbook-rails.js +7 -279
  31. data/lib/playbook/version.rb +2 -2
  32. metadata +2 -4
  33. data/app/pb_kits/playbook/pb_icon/docs/_icon_svg.html.erb +0 -5
  34. data/app/pb_kits/playbook/pb_logistic/_logistic.jsx +0 -120
@@ -12,8 +12,8 @@ import DateStacked from '../pb_date_stacked/_date_stacked'
12
12
 
13
13
  type DateTimeStackedProps = {
14
14
  id?: string,
15
- date: string,
16
- datetime: string,
15
+ date: Date,
16
+ datetime: Date,
17
17
  dark: boolean,
18
18
  timeZone?: string,
19
19
  }
@@ -34,7 +34,7 @@ test('renders time in default timezone', () => {
34
34
  test('renders time in timezone', () => {
35
35
  props.timeZone = 'Asia/Tokyo'
36
36
  const kit = renderKit(DateTimeStacked, props)
37
- expect(kit).toHaveTextContent(`${monthDayYear}2:00aJST`)
37
+ expect(kit).toHaveTextContent(`${monthDayYear}2:00aGMT+9`)
38
38
  })
39
39
 
40
40
  test('renders time in timezone', () => {
@@ -1,9 +1,9 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
- import DateTime from '../pb_kit/dateTime'
5
4
  import { buildCss, buildDataProps } from '../utilities/props'
6
5
  import { globalProps } from '../utilities/globalProps'
6
+ import DateTime from '../pb_kit/dateTime';
7
7
 
8
8
  import Body from '../pb_body/_body'
9
9
  import Title from '../pb_title/_title'
@@ -13,13 +13,12 @@ type DateYearStackedProps = {
13
13
  className?: string | string[],
14
14
  dark?: boolean,
15
15
  data?: string,
16
- date: string,
16
+ date: Date,
17
17
  id?: string,
18
18
  }
19
19
 
20
20
  const DateYearStacked = (props: DateYearStackedProps) => {
21
21
  const { align = 'left', className, dark = false, date, data={} } = props
22
- const dateTimestamp = new DateTime({ value: date })
23
22
  const css = classnames(
24
23
  buildCss('pb_date_year_stacked', align),
25
24
  globalProps(props),
@@ -29,15 +28,14 @@ const DateYearStacked = (props: DateYearStackedProps) => {
29
28
 
30
29
  return (
31
30
  <div {...dataProps}
32
- className={css}>
31
+ className={css}
32
+ >
33
33
  <Title
34
34
  dark={dark}
35
35
  size={4}
36
- text={`${dateTimestamp.toDay()} ${dateTimestamp
37
- .toMonth()
38
- .toUpperCase()}`}
36
+ text={`${DateTime.toDay(date)} ${DateTime.toMonth(date).toUpperCase()}`}
39
37
  />
40
- <Body color="light">{dateTimestamp.toYear()}</Body>
38
+ <Body color="light">{DateTime.toYear(date)}</Body>
41
39
  </div>
42
40
  )
43
41
  }
@@ -1,4 +1,3 @@
1
1
  <p><%= pb_rails("icon", props: { icon: "spinner", spin: true, fixed_width: true, size: "2x" }) %> <span>Spin</span></p>
2
2
  <br/>
3
3
  <p><%= pb_rails("icon", props: { icon: "spinner", pulse: true, fixed_width: true, size: "2x" }) %> <span>Pulse</span></p>
4
-
@@ -14,5 +14,3 @@
14
14
  parent element's css color properties."
15
15
  } ) %>
16
16
  </div>
17
-
18
-
@@ -1,15 +1,14 @@
1
1
  examples:
2
2
  rails:
3
- # - icon_default: Icon Default
4
- # - icon_rotate: Icon Rotate
5
- # - icon_flip: Icon Flip
6
- # - icon_animate: Icon Animation
7
- # - icon_pull: Icon Pull
8
- # - icon_border: Icon Border
9
- # - icon_sizes: Icon Sizes
10
- # - icon_custom: Icon Custom
11
- # - icon_fa_kit: Icon with FontAwesome Kit
12
- - icon_svg: Icon SVG
3
+ - icon_default: Icon Default
4
+ - icon_rotate: Icon Rotate
5
+ - icon_flip: Icon Flip
6
+ - icon_animate: Icon Animation
7
+ - icon_pull: Icon Pull
8
+ - icon_border: Icon Border
9
+ - icon_sizes: Icon Sizes
10
+ - icon_custom: Icon Custom
11
+ - icon_fa_kit: Icon with FontAwesome Kit
13
12
 
14
13
  react:
15
14
  - icon_default: Icon Default
@@ -1,15 +1,15 @@
1
1
  <% if object.custom_icon %>
2
- <%= object.embedded_svg(object.custom_icon) %>
2
+ <%= object.render_svg(object.custom_icon) %>
3
3
  <% elsif object.valid_emoji(object.icon) %>
4
4
  <span class="pb_icon_kit_emoji"><%= object.icon.html_safe %></span>
5
5
  <% else %>
6
6
  <%= content_tag(:i, nil,
7
7
  id: object.id,
8
8
  data: object.data,
9
- class: object.classname,
9
+ class: object.classname
10
10
  ) %>
11
11
  <%= content_tag(:span, nil,
12
12
  aria: { label: "#{object.icon} icon" }.merge(object.aria),
13
13
  hidden: true
14
14
  ) %>
15
- <% end %>
15
+ <% end %>
@@ -90,25 +90,6 @@ module Playbook
90
90
  end
91
91
  end
92
92
 
93
- def embedded_svg(icon_name)
94
- svg_path = Rails.application.config.respond_to?(:icon_path) ? Rails.application.config.icon_path : "app/assets/images"
95
- file_path = File.read(Rails.root.join(svg_path, "#{icon_name}.svg"))
96
-
97
- doc = Nokogiri::HTML::DocumentFragment.parse file_path
98
- svg = doc.at_css "svg"
99
-
100
- doc.to_html.html_safe
101
-
102
- size_factor = size.to_i
103
- if size_factor > 1
104
- pixel_size = size_factor * 16
105
- svg["width"] = pixel_size.to_s
106
- svg["height"] = pixel_size.to_s
107
- end
108
-
109
- raw doc
110
- end
111
-
112
93
  private
113
94
 
114
95
  def border_class
@@ -1,90 +1,376 @@
1
+ const ABBR_DAYS = ['SU', 'M', 'T', 'W', 'TH', 'F', 'S']
1
2
 
2
- import moment, { Moment } from 'moment'
3
- import 'moment-strftime'
4
- import 'moment-timezone'
3
+ const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
5
4
 
6
- type DateTimeType = {
7
- value: string | Date,
8
- zone?: string,
9
- }
5
+ const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
10
6
 
11
- const ABBR_DAYS = ['SU', 'M', 'T', 'W', 'TH', 'F', 'S']
7
+ const formatDate = (newDate: Date | string) => {
8
+ const isTimelessStringDate = typeof newDate === "string" && !newDate.includes("T")
12
9
 
13
- export default class DateTime {
14
- value: Moment & any
15
- constructor({ value, zone = 'America/New_York' }: DateTimeType) {
16
- this.value = this.convertToTimestampZone(value, zone)
10
+ if (isTimelessStringDate) {
11
+ const unhyphenatedDate = new Date((newDate as string).replace(/-/g, "/"))
12
+ return unhyphenatedDate
17
13
  }
18
14
 
19
- convertToTimestampZone(value: string | Date, zone: string) {
20
- return moment(value).tz(zone)
21
- }
15
+ return new Date(newDate)
16
+ }
22
17
 
23
- convertToTimezone() {
24
- return this.value.strftime('%Z')
18
+ export const toMinute = (newDate: Date | string, timeZone?: string): string => {
19
+ const date = formatDate(newDate)
20
+ if (timeZone) {
21
+ return date.toLocaleTimeString(undefined, { timeZone, hour: "2-digit", minute: "2-digit" }).slice(3, 5);
22
+ } else {
23
+ return date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" }).slice(3, 5);
25
24
  }
25
+ }
26
26
 
27
- toCustomFormat(format = '%-m/%-d') {
28
- return this.value.strftime(format)
27
+ export const toHour = (newDate: Date | string, timeZone?: string): string => {
28
+ const date = formatDate(newDate)
29
+ if (timeZone) {
30
+ return date.toLocaleTimeString(undefined, { timeZone, hour: "numeric" }).split(' ')[0];
31
+ } else {
32
+ return date.toLocaleTimeString(undefined, { hour: "numeric" }).split(' ')[0];
29
33
  }
34
+ }
30
35
 
31
- toYear() {
32
- return this.value.strftime('%Y')
33
- }
36
+ export const toDay = (newDate: Date | string, timeZone?: string): number => {
37
+ if (timeZone) {
38
+ const date = new Date(formatDate(newDate).toLocaleString(undefined, { timeZone }));
39
+ return date.getDate()
40
+ } else {
41
+ const date = formatDate(newDate)
42
+ return date.getDate()
43
+ }
44
+ }
34
45
 
35
- toMonth() {
36
- return this.value.strftime('%b')
37
- }
46
+ export const toDayAbbr = (newDate: Date | string): string => {
47
+ const date = formatDate(newDate)
48
+ return ABBR_DAYS[date.getUTCDay()]
49
+ }
38
50
 
39
- toMonthNum() {
40
- return this.value.strftime('%-m')
41
- }
51
+ export const toWeekday = (newDate: Date | string): string => {
52
+ const date = formatDate(newDate)
53
+ return days[date.getUTCDay()]
54
+ }
42
55
 
43
- toMonthFull() {
44
- return this.value.strftime('%B')
45
- }
56
+ export const toMonth = (newDate: Date | string, timeZone?: string): string => {
57
+ if (timeZone) {
58
+ const date = new Date(formatDate(newDate).toLocaleString(undefined, { timeZone }));
59
+ return months[date.getUTCMonth()]
60
+ } else {
61
+ const date = formatDate(newDate)
62
+ return months[date.getUTCMonth()]
63
+ }
64
+ }
46
65
 
47
- toDay() {
48
- return this.value.strftime('%e')
49
- }
66
+ export const toMonthNum = (newDate: Date | string): number => {
67
+ const date = formatDate(newDate)
68
+ return date.getUTCMonth() +1
69
+ }
50
70
 
51
- toDayAbbr() {
52
- return ABBR_DAYS[this.value.day()]
53
- }
71
+ export const toYear = (newDate: Date | string, timeZone?: string): number => {
72
+ if (timeZone) {
73
+ const date = new Date(newDate.toLocaleString(undefined, { timeZone }));
74
+ return date.getUTCFullYear()
75
+ } else {
76
+ const date = new Date(newDate)
77
+ return date.getUTCFullYear()
78
+ }
79
+ }
54
80
 
55
- toWeekday() {
56
- return this.value.strftime('%a')
81
+ export const toTime = (newDate: Date | string, timeZone?: string): string => {
82
+ const date = formatDate(newDate)
83
+ if (timeZone) {
84
+ return date.toLocaleTimeString(undefined, { timeZone, timeStyle: "short" }).split(' ')[0];
85
+ } else {
86
+ return date.toLocaleTimeString(undefined, { timeStyle: "short" }).split(' ')[0];
57
87
  }
88
+ }
58
89
 
59
- toHour() {
60
- return this.value.strftime('%l')
61
- }
90
+ export const toMeridiem = (newDate: Date | string, timeZone?: string): string => {
91
+ const date = formatDate(newDate)
92
+ if (timeZone) {
93
+ return date.toLocaleString(undefined, { timeZone, hour12: true }).slice(-2).charAt(0).toLocaleLowerCase();
94
+ } else {
95
+ return date.toLocaleString(undefined, { hour12: true }).slice(-2).charAt(0).toLocaleLowerCase();
96
+ }
97
+ }
62
98
 
63
- toMinute() {
64
- return this.value.strftime('%M')
65
- }
99
+ export const toTimeZone = (newDate: Date | string, timeZone?: string): string => {
100
+ const date = formatDate(newDate)
101
+ if (timeZone) {
102
+ return date.toLocaleString(undefined, { timeZone, timeZoneName: "short" }).split(' ')[3];
103
+ } else {
104
+ return date.toLocaleString(undefined, { timeZoneName: "short" }).split(' ')[3];
105
+ }
106
+ }
66
107
 
67
- toMeridian() {
68
- return this.value.strftime('%P')[0]
69
- }
108
+ export const toTimeWithMeridiem = (newDate: Date | string, timeZone: string): string => {
109
+ const date = formatDate(newDate)
110
+ return `${toTime(date, timeZone)}${toMeridiem(date, timeZone)}`;
111
+ }
70
112
 
71
- toIso() {
72
- return this.value.toISOString()
73
- }
113
+ export const toIso = (newDate: Date | string): string => {
114
+ const date = formatDate(newDate)
115
+ return date.toISOString()
116
+ }
74
117
 
75
- toTime() {
76
- const time = this.value.strftime('%I:%M')
118
+ export const fromNow = (newDate: Date | string): string => {
119
+ const startDate = formatDate(newDate).getTime()
120
+ const endDate = new Date().getTime()
121
+ const elapsedTime = endDate - startDate
122
+ let elapsedTimeString = `${Math.round(elapsedTime / (365.25 * 24 * 60 * 60 * 1000))} years ago.`; // 730+ days
77
123
 
78
- // strftime adds a leading 0 on single hour times. ie 08:31.
79
- // this removes that 0 to match the rails kit.
80
- return time.charAt() === '0' ? time.slice(1) : time
81
- }
124
+ const elapsedTimeData = [
125
+ { min: 0, max: 44999, value: "a few seconds ago" }, // 0-44 seconds
126
+ { min: 45000, max: 89999, value: "a minute ago" }, // 45-89 seconds
127
+ { min: 90000, max: 2649999, value: `${Math.round(elapsedTime / 60000)} minutes ago`}, // 90s-44 minutes
128
+ { min: 2650000, max: 7299999, value: "an hour ago" }, // 45-120 minutes
129
+ { min: 7300000, max: 75699999, value: `${Math.round(elapsedTime / 3600000)} hours ago`}, // 2-21 hours
130
+ { min: 75700000, max: 172899999, value: "a day ago" }, // 22-48 hours
131
+ { min: 172900000, max: 2169999999, value: `${Math.round(elapsedTime / 86400000)} days ago`}, // 2-25 days
132
+ { min: 2170000000, max: 5184999999, value: "a month ago"}, // 26-60 days
133
+ { min: 5185000000, max: 27561699999, value: `${Math.round(elapsedTime / 30.44 * 24 * 60 * 60 * 1000)} months ago`}, // 60-319 days
134
+ { min: 27561700000, max: 63072999999, value: "a year ago"}, // 320-730 days
135
+ ];
82
136
 
83
- toTimezone() {
84
- return this.value.strftime('%Z')
137
+ for (const timeDate of elapsedTimeData) {
138
+ if (elapsedTime >= timeDate.min && elapsedTime <= timeDate.max) {
139
+ elapsedTimeString = timeDate.value;
140
+ break;
141
+ }
85
142
  }
86
143
 
87
- toTimeWithMeridian() {
88
- return this.toTime() + this.toMeridian()
144
+ return elapsedTimeString
145
+ }
146
+
147
+ export const toCustomFormat = (newDate: Date | string, format = 'month_day'): string => {
148
+ const date = formatDate(newDate)
149
+ if (format == "month_day") {
150
+ return `${toMonthNum(date)}/${toDay(date)}`
151
+ } else {
152
+ return `${date.toLocaleString(undefined, { month: "short" })} ${toDay(date)}`
89
153
  }
90
154
  }
155
+
156
+ // For quickPick.tsx
157
+ // Yesterday
158
+ export const getYesterdayDate = (newDate: Date | string): Date => {
159
+ const today = formatDate(newDate)
160
+ const yesterday = new Date()
161
+ yesterday.setDate(today.getDate() - 1)
162
+
163
+ return yesterday
164
+ }
165
+
166
+ // Weeks
167
+ export const getFirstDayOfWeek = (newDate: Date | string): Date => {
168
+ const today = formatDate(newDate)
169
+ const dayOfWeek = today.getDay()
170
+ // Replicate Moment.js: Start of week (Monday) has a time of 00:00:00
171
+ const firstDayOfWeek = new Date(today.setHours(0, 0, 0))
172
+ const isSunday = dayOfWeek === 0
173
+
174
+ const daysToSubtract = isSunday ? 6 : (dayOfWeek - 1)
175
+ firstDayOfWeek.setDate(today.getDate() - daysToSubtract)
176
+
177
+ return firstDayOfWeek
178
+ }
179
+
180
+ export const getLastDayOfWeek = (newDate: Date | string): Date => {
181
+ const today = formatDate(newDate)
182
+ const dayOfWeek = today.getDay()
183
+ // Replicate Moment.js: End of week (Sunday) has a time of 23:59:59
184
+ const lastDayOfWeek = new Date(today.setHours(23, 59, 59, 0))
185
+ const isSunday = dayOfWeek === 0
186
+
187
+ const daysToAdd = isSunday ? 0 : (7 - dayOfWeek)
188
+ lastDayOfWeek.setDate(today.getDate() + daysToAdd)
189
+
190
+ return lastDayOfWeek
191
+ }
192
+
193
+ export const getPreviousWeekStartDate = (newDate: Date | string): Date => {
194
+ const firstDayOfWeek = getFirstDayOfWeek(newDate)
195
+ const firstDayOfPreviousWeek = new Date(
196
+ firstDayOfWeek.getFullYear(),
197
+ firstDayOfWeek.getMonth(),
198
+ firstDayOfWeek.getDate() - 7
199
+ )
200
+
201
+ return firstDayOfPreviousWeek
202
+ }
203
+
204
+ export const getPreviousWeekEndDate = (newDate: Date | string): Date => {
205
+ const lastDayOfWeek = getLastDayOfWeek(newDate)
206
+ const lastDayOfPreviousWeek = new Date(
207
+ lastDayOfWeek.getFullYear(),
208
+ lastDayOfWeek.getMonth(),
209
+ lastDayOfWeek.getDate() - 7,
210
+ lastDayOfWeek.getHours(),
211
+ lastDayOfWeek.getMinutes(),
212
+ lastDayOfWeek.getSeconds()
213
+ )
214
+
215
+ return lastDayOfPreviousWeek
216
+ }
217
+
218
+ // Months
219
+ export const getMonthStartDate = (newDate: Date | string): Date => {
220
+ const date = formatDate(newDate)
221
+ const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1)
222
+
223
+ return firstDayOfMonth
224
+ }
225
+
226
+ export const getMonthEndDate = (newDate: Date | string): Date => {
227
+ const date = formatDate(newDate)
228
+ // Replicate Moment.js: End of month has a time of 23:59:59
229
+ const lastDayOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59)
230
+
231
+ return lastDayOfMonth
232
+ }
233
+
234
+ export const getPreviousMonthStartDate = (newDate: Date | string): Date => {
235
+ const firstDayOfMonth = getMonthStartDate(newDate)
236
+ const firstDayOfPreviousMonth = new Date(
237
+ firstDayOfMonth.getFullYear(),
238
+ firstDayOfMonth.getMonth() - 1,
239
+ firstDayOfMonth.getDate()
240
+ )
241
+
242
+ return firstDayOfPreviousMonth
243
+ }
244
+
245
+ export const getPreviousMonthEndDate = (newDate: Date | string): Date => {
246
+ const lastDayOfMonth = getMonthEndDate(newDate)
247
+ const lastDayOfPreviousMonth = new Date(
248
+ lastDayOfMonth.getFullYear(),
249
+ lastDayOfMonth.getMonth() - 1,
250
+ lastDayOfMonth.getDate(),
251
+ lastDayOfMonth.getHours(),
252
+ lastDayOfMonth.getMinutes(),
253
+ lastDayOfMonth.getSeconds()
254
+ )
255
+
256
+ return lastDayOfPreviousMonth
257
+ }
258
+
259
+ // Quarters
260
+ export const getQuarterStartDate = (newDate: Date | string): Date => {
261
+ const date = formatDate(newDate)
262
+ const quarter = Math.floor(date.getMonth() / 3)
263
+ const startOfQuarter = new Date(date.getFullYear(), quarter * 3, 1)
264
+
265
+ return startOfQuarter
266
+ }
267
+
268
+ export const getQuarterEndDate = (newDate: Date | string): Date => {
269
+ const date = formatDate(newDate)
270
+ const quarter = Math.floor(date.getMonth() / 3)
271
+ const startOfNextQuarter = new Date(date.getFullYear(), (quarter + 1) * 3, 1)
272
+ // Replicate Moment.js: End of quarter has a time of 23:59:59
273
+ const endOfQuarter = new Date(startOfNextQuarter.getTime() - 1)
274
+
275
+ return endOfQuarter
276
+ }
277
+
278
+ export const getPreviousQuarterStartDate = (newDate: Date | string): Date => {
279
+ const startOfQuarter = getQuarterStartDate(newDate)
280
+ const firstDayOfPreviousQuarter = new Date(
281
+ startOfQuarter.getFullYear(),
282
+ startOfQuarter.getMonth() - 3,
283
+ startOfQuarter.getDate()
284
+ )
285
+
286
+ return firstDayOfPreviousQuarter
287
+ }
288
+
289
+ export const getPreviousQuarterEndDate = (newDate: Date | string): Date => {
290
+ const endOfQuarter = getQuarterEndDate(newDate)
291
+ const lastDayOfPreviousQuarter = new Date(
292
+ endOfQuarter.getFullYear(),
293
+ endOfQuarter.getMonth() - 3,
294
+ endOfQuarter.getDate(),
295
+ endOfQuarter.getHours(),
296
+ endOfQuarter.getMinutes(),
297
+ endOfQuarter.getSeconds()
298
+ )
299
+
300
+ return lastDayOfPreviousQuarter
301
+ }
302
+
303
+ // Years
304
+ export const getYearStartDate = (newDate: Date | string): Date => {
305
+ const date = formatDate(newDate)
306
+ const startOfYear = new Date(date.getFullYear(), 0, 1)
307
+
308
+ return startOfYear
309
+ }
310
+
311
+ export const getYearEndDate = (newDate: Date | string): Date => {
312
+ const date = formatDate(newDate)
313
+ const endOfYear = new Date(date.getFullYear(), 11, 31, 23, 59, 59)
314
+
315
+ return endOfYear
316
+ }
317
+
318
+ export const getPreviousYearStartDate = (newDate: Date | string): Date => {
319
+ const startOfYear = getYearStartDate(newDate)
320
+ const firstDayOfPreviousYear = new Date(
321
+ startOfYear.getFullYear() - 1,
322
+ startOfYear.getMonth(),
323
+ startOfYear.getDate()
324
+ )
325
+
326
+ return firstDayOfPreviousYear
327
+ }
328
+
329
+ export const getPreviousYearEndDate = (newDate: Date | string): Date => {
330
+ const endOfYear = getYearEndDate(newDate)
331
+ const lastDayOfPreviousYear = new Date(
332
+ endOfYear.getFullYear() - 1,
333
+ endOfYear.getMonth(),
334
+ endOfYear.getDate(),
335
+ endOfYear.getHours(),
336
+ endOfYear.getMinutes(),
337
+ endOfYear.getSeconds()
338
+ )
339
+
340
+ return lastDayOfPreviousYear
341
+ }
342
+
343
+ export default {
344
+ toMinute,
345
+ toHour,
346
+ toDay,
347
+ toDayAbbr,
348
+ toWeekday,
349
+ toMonth,
350
+ toMonthNum,
351
+ toYear,
352
+ toTime,
353
+ toMeridiem,
354
+ toTimeZone,
355
+ toTimeWithMeridiem,
356
+ toIso,
357
+ fromNow,
358
+ toCustomFormat,
359
+ getYesterdayDate,
360
+ getFirstDayOfWeek,
361
+ getLastDayOfWeek,
362
+ getPreviousWeekStartDate,
363
+ getPreviousWeekEndDate,
364
+ getMonthStartDate,
365
+ getMonthEndDate,
366
+ getPreviousMonthStartDate,
367
+ getPreviousMonthEndDate,
368
+ getQuarterStartDate,
369
+ getQuarterEndDate,
370
+ getPreviousQuarterStartDate,
371
+ getPreviousQuarterEndDate,
372
+ getYearStartDate,
373
+ getYearEndDate,
374
+ getPreviousYearStartDate,
375
+ getPreviousYearEndDate
376
+ }