ไม่มีชื่อบทความ
การจัดการ Timezone และการ Validate ข้อมูลลงเวลา
1. Timezone ที่ใช้ในระบบ
ระบบกำหนดให้ทุกการลงเวลาใช้ Timezone แบบตายตัวคือ:
- Asia/Bangkok (UTC+7)
เหตุผล: เพื่อให้เวลาที่ลงทะเบียนตรงกับเวลาจริงในประเทศไทย โดยไม่ขึ้นกับว่า user อยู่โซนเวลาไหน
2. ตรวจสอบ Timezone ฝั่ง Client
สามารถตรวจ timezone ของเครื่องผู้ใช้ได้ผ่าน JavaScript API:
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log('Your timezone:', userTimezone);
- ถ้า
userTimezone !== 'Asia/Bangkok'สามารถแสดงคำเตือนเบา ๆ ว่า "เวลาที่แสดงอาจคลาดเคลื่อน" - แต่สุดท้ายการบันทึกจริงยึดเวลาฝั่ง Server (Date.now()) เสมอ
3. Validate เงื่อนไขพิเศษก่อนส่งข้อมูล
3.1 ไม่อนุญาตให้ส่งเวลาที่อยู่ในอนาคต
Server จะสร้าง timestamp ตอนรับ request อยู่แล้ว ดังนั้น Client ไม่ต้องส่งเวลา แต่ถ้าเพิ่มฟีเจอร์เลือกเวลาในอนาคต จะต้อง block ไม่ให้เลือกเวลาอนาคต
3.2 จำกัดการลงเวลาให้ลงได้ทุก 5 นาที
ตัวอย่างเช่น:
- ลงเวลา 08:00, 08:05, 08:10, ... ได้
- แต่ไม่สามารถลง 08:02, 08:07 ได้
หลักการคือให้ timestamp ต้องหาร 300000 (5 นาที) ลงตัว
4. โค้ด Helper: validateClockPayload()
สร้างไฟล์:
src/utils/validateClockPayload.js
เนื้อหา:
// src/utils/validateClockPayload.js
/**
* Validate payload ก่อนส่ง API ลงเวลา
* @param {string} employeeCode
* @param {string} action (Check-in | Check-out)
* @param {Date} dateObject (เวลาปัจจุบันฝั่ง client)
*/
export function validateClockPayload(employeeCode, action, dateObject) {
if (!employeeCode || typeof employeeCode !== 'string') return false;
if (!['Check-in', 'Check-out'].includes(action)) return false;
const timestamp = dateObject.getTime();
const now = Date.now();
// ไม่ให้อนาคตเกิน 1 นาที
if (timestamp - now > 60000) return false;
// ให้ลงเวลาได้ทุก 5 นาที (300,000 ms)
if (timestamp % 300000 !== 0) return false;
return true;
}
5. ตัวอย่าง Unit Test ด้วย Jest
สร้างไฟล์:
src/utils/__tests__/validateClockPayload.test.js
เนื้อหา:
import { validateClockPayload } from '../validateClockPayload';
test('valid input should pass', () => {
const date = new Date(Math.floor(Date.now() / 300000) * 300000);
expect(validateClockPayload('E123', 'Check-in', date)).toBe(true);
});
test('invalid action should fail', () => {
const date = new Date();
expect(validateClockPayload('E123', 'INVALID', date)).toBe(false);
});
test('future time should fail', () => {
const date = new Date(Date.now() + 120000); // +2 นาที
expect(validateClockPayload('E123', 'Check-in', date)).toBe(false);
});
test('not aligned 5 min should fail', () => {
const date = new Date(Date.now());
expect(validateClockPayload('E123', 'Check-in', date)).toBe(false);
});
6. แนวทาง UI แสดงเวลาปัจจุบัน
ในหน้า TimeClockForm สามารถแสดงเวลาปัจจุบันให้ผู้ใช้เห็นด้วย เช่น:
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => setCurrentTime(new Date()), 60000);
return () => clearInterval(timer);
}, []);
return (
<p className="text-center text-gray-600 text-sm">
เวลาปัจจุบัน: {currentTime.toLocaleTimeString('th-TH', { timeZone: 'Asia/Bangkok' })}
</p>
);
หมายเหตุ:
- อัปเดตเวลาใหม่ทุก ๆ 1 นาที (ไม่ต้อง real-time วินาที)
- ใช้
timeZone: 'Asia/Bangkok'ในtoLocaleTimeStringเพื่อให้แม่นยำ
หมายเหตุ: หลังขั้นตอนนี้ ระบบจะเริ่มรองรับการตรวจสอบเวลาลงงานได้ละเอียดขึ้น และรองรับการแสดงเวลาให้ตรงกับประเทศไทยเสมอ