@@ -19,6 +19,8 @@ type TrendBucket = {
1919 end : Date ;
2020} ;
2121
22+ const CHINA_OFFSET_MS = 8 * 60 * 60 * 1000 ;
23+
2224@Injectable ( )
2325export class DashboardService {
2426 constructor (
@@ -29,8 +31,17 @@ export class DashboardService {
2931
3032 async getOverview ( ) {
3133 const now = new Date ( ) ;
32- const todayStart = new Date ( now . getFullYear ( ) , now . getMonth ( ) , now . getDate ( ) ) ;
33- const monthStart = new Date ( now . getFullYear ( ) , now . getMonth ( ) , 1 ) ;
34+ const chinaNow = this . getChinaShiftedDate ( now ) ;
35+ const todayStart = this . createChinaBoundaryDate (
36+ chinaNow . getUTCFullYear ( ) ,
37+ chinaNow . getUTCMonth ( ) ,
38+ chinaNow . getUTCDate ( ) ,
39+ ) ;
40+ const monthStart = this . createChinaBoundaryDate (
41+ chinaNow . getUTCFullYear ( ) ,
42+ chinaNow . getUTCMonth ( ) ,
43+ 1 ,
44+ ) ;
3445
3546 const [
3647 todayRevenue ,
@@ -83,12 +94,12 @@ export class DashboardService {
8394 const rows = await this . dataSource
8495 . getRepository ( SaleOrderEntity )
8596 . createQueryBuilder ( 'saleOrder' )
86- . select ( [ "datetime( saleOrder.created_at, 'localtime') AS createdAt" , 'saleOrder.total_amount AS totalAmount' ] )
87- . where ( "datetime( saleOrder.created_at, 'localtime') >= :start" , {
88- start : this . formatSqliteDateTime ( start ) ,
97+ . select ( [ ' saleOrder.created_at AS createdAt' , 'saleOrder.total_amount AS totalAmount' ] )
98+ . where ( ' saleOrder.created_at >= :start' , {
99+ start : this . formatUtcStorageDateTime ( start ) ,
89100 } )
90- . andWhere ( "datetime( saleOrder.created_at, 'localtime') <= :end" , {
91- end : this . formatSqliteDateTime ( end ) ,
101+ . andWhere ( ' saleOrder.created_at <= :end' , {
102+ end : this . formatUtcStorageDateTime ( end ) ,
92103 } )
93104 . getRawMany < { createdAt : string ; totalAmount : number } > ( ) ;
94105
@@ -99,7 +110,7 @@ export class DashboardService {
99110 } ) ) ;
100111
101112 rows . forEach ( ( row ) => {
102- const createdAt = new Date ( row . createdAt ) ;
113+ const createdAt = this . parseUtcStorageDateTime ( row . createdAt ) ;
103114 const bucketIndex = buckets . findIndex (
104115 ( bucket ) => createdAt >= bucket . start && createdAt <= bucket . end ,
105116 ) ;
@@ -207,11 +218,11 @@ export class DashboardService {
207218 . getRepository ( SaleOrderEntity )
208219 . createQueryBuilder ( 'saleOrder' )
209220 . select ( 'COALESCE(SUM(saleOrder.total_amount), 0)' , 'amount' )
210- . where ( "datetime( saleOrder.created_at, 'localtime') >= :start" , {
211- start : this . formatSqliteDateTime ( start ) ,
221+ . where ( ' saleOrder.created_at >= :start' , {
222+ start : this . formatUtcStorageDateTime ( start ) ,
212223 } )
213- . andWhere ( "datetime( saleOrder.created_at, 'localtime') <= :end" , {
214- end : this . formatSqliteDateTime ( end ) ,
224+ . andWhere ( ' saleOrder.created_at <= :end' , {
225+ end : this . formatUtcStorageDateTime ( end ) ,
215226 } )
216227 . getRawOne < { amount : number } > ( ) ;
217228
@@ -283,20 +294,30 @@ export class DashboardService {
283294 }
284295
285296 private buildTrendBuckets ( period : 'day' | 'week' | 'month' ) : TrendBucket [ ] {
286- const now = new Date ( ) ;
297+ const chinaNow = this . getChinaShiftedDate ( ) ;
287298
288299 if ( period === 'week' ) {
289300 return Array . from ( { length : 8 } , ( _ , index ) => {
290- const start = new Date ( now ) ;
291- start . setDate ( now . getDate ( ) - ( 7 - index ) * 7 ) ;
292- start . setHours ( 0 , 0 , 0 , 0 ) ;
293-
294- const end = new Date ( start ) ;
295- end . setDate ( start . getDate ( ) + 6 ) ;
296- end . setHours ( 23 , 59 , 59 , 999 ) ;
301+ const startChina = new Date ( Date . UTC (
302+ chinaNow . getUTCFullYear ( ) ,
303+ chinaNow . getUTCMonth ( ) ,
304+ chinaNow . getUTCDate ( ) - ( 7 - index ) * 7 ,
305+ ) ) ;
306+ const endChina = new Date ( Date . UTC (
307+ startChina . getUTCFullYear ( ) ,
308+ startChina . getUTCMonth ( ) ,
309+ startChina . getUTCDate ( ) + 6 ,
310+ 23 ,
311+ 59 ,
312+ 59 ,
313+ 999 ,
314+ ) ) ;
315+
316+ const start = new Date ( startChina . getTime ( ) - CHINA_OFFSET_MS ) ;
317+ const end = new Date ( endChina . getTime ( ) - CHINA_OFFSET_MS ) ;
297318
298319 return {
299- label : `${ start . getMonth ( ) + 1 } /${ start . getDate ( ) } ` ,
320+ label : `${ startChina . getUTCMonth ( ) + 1 } /${ startChina . getUTCDate ( ) } ` ,
300321 start,
301322 end,
302323 } ;
@@ -305,30 +326,73 @@ export class DashboardService {
305326
306327 if ( period === 'month' ) {
307328 return Array . from ( { length : 12 } , ( _ , index ) => {
308- const start = new Date ( now . getFullYear ( ) , now . getMonth ( ) - ( 11 - index ) , 1 ) ;
309- const end = new Date ( start . getFullYear ( ) , start . getMonth ( ) + 1 , 0 , 23 , 59 , 59 , 999 ) ;
329+ const startChina = new Date ( Date . UTC (
330+ chinaNow . getUTCFullYear ( ) ,
331+ chinaNow . getUTCMonth ( ) - ( 11 - index ) ,
332+ 1 ,
333+ ) ) ;
334+ const endChina = new Date ( Date . UTC (
335+ startChina . getUTCFullYear ( ) ,
336+ startChina . getUTCMonth ( ) + 1 ,
337+ 0 ,
338+ 23 ,
339+ 59 ,
340+ 59 ,
341+ 999 ,
342+ ) ) ;
343+ const start = new Date ( startChina . getTime ( ) - CHINA_OFFSET_MS ) ;
344+ const end = new Date ( endChina . getTime ( ) - CHINA_OFFSET_MS ) ;
310345
311346 return {
312- label : `${ start . getFullYear ( ) } -${ String ( start . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) } ` ,
347+ label : `${ startChina . getUTCFullYear ( ) } -${ String ( startChina . getUTCMonth ( ) + 1 ) . padStart ( 2 , '0' ) } ` ,
313348 start,
314349 end,
315350 } ;
316351 } ) ;
317352 }
318353
319354 return Array . from ( { length : 7 } , ( _ , index ) => {
320- const start = new Date ( now . getFullYear ( ) , now . getMonth ( ) , now . getDate ( ) - ( 6 - index ) ) ;
321- const end = new Date ( start ) ;
322- end . setHours ( 23 , 59 , 59 , 999 ) ;
355+ const startChina = new Date ( Date . UTC (
356+ chinaNow . getUTCFullYear ( ) ,
357+ chinaNow . getUTCMonth ( ) ,
358+ chinaNow . getUTCDate ( ) - ( 6 - index ) ,
359+ ) ) ;
360+ const endChina = new Date ( Date . UTC (
361+ startChina . getUTCFullYear ( ) ,
362+ startChina . getUTCMonth ( ) ,
363+ startChina . getUTCDate ( ) ,
364+ 23 ,
365+ 59 ,
366+ 59 ,
367+ 999 ,
368+ ) ) ;
369+ const start = new Date ( startChina . getTime ( ) - CHINA_OFFSET_MS ) ;
370+ const end = new Date ( endChina . getTime ( ) - CHINA_OFFSET_MS ) ;
323371
324372 return {
325- label : `${ start . getMonth ( ) + 1 } /${ start . getDate ( ) } ` ,
373+ label : `${ startChina . getUTCMonth ( ) + 1 } /${ startChina . getUTCDate ( ) } ` ,
326374 start,
327375 end,
328376 } ;
329377 } ) ;
330378 }
331379
380+ private getChinaShiftedDate ( date = new Date ( ) ) {
381+ return new Date ( date . getTime ( ) + CHINA_OFFSET_MS ) ;
382+ }
383+
384+ private createChinaBoundaryDate (
385+ year : number ,
386+ month : number ,
387+ day : number ,
388+ hours = 0 ,
389+ minutes = 0 ,
390+ seconds = 0 ,
391+ milliseconds = 0 ,
392+ ) {
393+ return new Date ( Date . UTC ( year , month , day , hours , minutes , seconds , milliseconds ) - CHINA_OFFSET_MS ) ;
394+ }
395+
332396 private buildExpiryWarning ( product : ProductEntity , now : Date ) {
333397 if ( ! product . producedAt || ! product . shelfLife || product . shelfLife <= 0 ) {
334398 return null ;
@@ -364,14 +428,12 @@ export class DashboardService {
364428 } ;
365429 }
366430
367- private formatSqliteDateTime ( date : Date ) {
368- const year = date . getFullYear ( ) ;
369- const month = String ( date . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) ;
370- const day = String ( date . getDate ( ) ) . padStart ( 2 , '0' ) ;
371- const hours = String ( date . getHours ( ) ) . padStart ( 2 , '0' ) ;
372- const minutes = String ( date . getMinutes ( ) ) . padStart ( 2 , '0' ) ;
373- const seconds = String ( date . getSeconds ( ) ) . padStart ( 2 , '0' ) ;
431+ private formatUtcStorageDateTime ( date : Date ) {
432+ return date . toISOString ( ) . slice ( 0 , 19 ) . replace ( 'T' , ' ' ) ;
433+ }
374434
375- return `${ year } -${ month } -${ day } ${ hours } :${ minutes } :${ seconds } ` ;
435+ private parseUtcStorageDateTime ( value : string ) {
436+ const normalized = value . trim ( ) . replace ( ' ' , 'T' ) ;
437+ return new Date ( normalized . endsWith ( 'Z' ) ? normalized : `${ normalized } Z` ) ;
376438 }
377439}
0 commit comments