Jiff ไลบรารีวันที่และเวลาสำหรับ Rust
(github.com/BurntSushi)- Jiff เป็นไลบรารีวันที่และเวลาสำหรับ Rust โดยมุ่งให้มีชนิดพื้นฐานด้านวันที่และเวลาระดับสูงที่ใช้งานผิดได้ยาก และมีประสิทธิภาพที่สมเหตุสมผล
- ฟีเจอร์หลักคือการผสานกับ Time Zone Database โดยอัตโนมัติ, การคำนวณและการปัดเศษที่รับรู้ DST, การฟอร์แมตและพาร์สวันที่และเวลาพร้อมเขตเวลาแบบไม่สูญเสียข้อมูล และรองรับ Serde แบบเลือกเปิดได้
- การออกแบบ API ได้รับอิทธิพลอย่างมากจาก Temporal ซึ่งเป็นข้อเสนอของ TC39 เพื่อปรับปรุงการจัดการวันที่และเวลาของ JavaScript
- เดิมที Jiff 1.0 ตั้งเป้าปล่อยในช่วงฤดูร้อนปี 2025 แต่ ณ เมษายน 2026 กำหนดการเลื่อนออกไปแล้ว และปัจจุบันยังไม่มีไทม์ไลน์สำหรับการปล่อย 1.0
- ประสิทธิภาพเป็นเป้าหมายสำคัญ แต่ให้ความสำคัญกับ ความเข้าใจได้ของ API และความถูกต้องก่อน และบน Unix จะทำตามนโยบาย dependency แบบอนุรักษนิยมที่ตั้งใจคงไว้ที่ 0 dependency
โมเดลวันที่และเวลาที่ Jiff มีให้
- Jiff เป็นไลบรารีสำหรับจัดการวันที่และเวลาใน Rust โดยเน้นการให้ชนิดพื้นฐานระดับสูงที่ใช้งานผิดได้ยาก
- ฟีเจอร์หลักที่รองรับ
- การผสานกับ Time Zone Database แบบอัตโนมัติและราบรื่น
- การคำนวณและการปัดเศษที่รับรู้ DST
- การฟอร์แมตและพาร์สแบบไม่สูญเสียข้อมูล สำหรับวันที่และเวลาพร้อมเขตเวลา
- รองรับ
serdeแบบเลือกเปิดได้
- การออกแบบ API ได้รับอิทธิพลอย่างมากจาก Temporal ซึ่งเป็นข้อเสนอของ TC39 เพื่อปรับปรุงการจัดการวันที่และเวลาของ JavaScript
- ใช้ไลเซนส์คู่ MIT หรือ UNLICENSE
เอกสารและตัวอย่างการใช้งาน
- เอกสารและข้อมูลที่เกี่ยวข้อง
- เอกสาร API บน docs.rs
- เอกสารเปรียบเทียบกับ
chrono,time,hifitime,icu - เอกสารเหตุผลเบื้องหลังการออกแบบ API ของ Jiff
- เอกสารการรองรับแพลตฟอร์ม
- บันทึกการเปลี่ยนแปลง
- ตัวอย่างพื้นฐานคือพาร์สสตริงเวลา RFC 3339 แล้วแปลงเป็นวันที่และเวลาพร้อมเขตเวลา จากนั้นบวกช่วงเวลา แล้วแสดงผลเป็นสตริงแบบไม่สูญเสียข้อมูล
- พาร์ส
"2024-07-11T01:14:00Z"เป็นTimestamp - แปลงเป็นเขตเวลา
America/New_York - บวก
1.month().hours(2) - สตริงผลลัพธ์คือ
"2024-08-10T23:14:00-04:00[America/New_York]" - เวลา UTC ในรูปแบบ RFC 3339 คือ
"2024-08-11T03:14:00Z"
- พาร์ส
การติดตั้งและลำดับการรันพื้นฐาน
- Jiff อยู่บน crates.io และสามารถใช้งานได้โดยเพิ่ม
jiffเข้าไปใน dependency ของCargo.tomlในโปรเจกต์ Rust - คำสั่งเพิ่มแบบง่ายคือ
cargo add jiff - ลำดับตัวอย่างเต็มใน README
- สร้างโปรเจกต์ใหม่ด้วย
cargo new jiff-example - เพิ่ม dependency ด้วย
cargo add jiff - ใน
src/main.rsปัดเศษเวลาปัจจุบันเป็นระดับวินาทีด้วยZoned::now().round(Unit::Second)? - รันด้วย
cargo run
- สร้างโปรเจกต์ใหม่ด้วย
- เอาต์พุตตัวอย่างแสดงรูปแบบที่มีเขตเวลา เช่น
2024-07-10T19:54:20-04:00[America/New_York] - การรันครั้งแรกจะมีเอาต์พุตการคอมไพล์มากกว่า แต่ในการรันครั้งถัดไปไม่จำเป็นต้องคอมไพล์ dependency ซ้ำ
Feature flag และแผน 1.0
- Jiff มี crate feature หลายรายการสำหรับปรับว่าจะรองรับ Rust standard library, รองรับ
serdeและจะฝัง Time Zone Database ไว้ในไบนารีหรือไม่ - รายการ feature flag ทั้งหมดที่รองรับอยู่ในส่วน “crate features” ของเอกสาร
- แผนเดิมสำหรับการปล่อย Jiff 1.0 คือช่วงฤดูร้อนปี 2025 แต่ ณ เมษายน 2026 กำหนดการเลื่อนออกไปแล้ว และปัจจุบันยังไม่มีไทม์ไลน์การปล่อย
- หลังปล่อย 1.0 มีแผนจะคง API ไว้อย่างไม่มีกำหนด โดยมีเป้าหมายให้ผู้ใช้ใช้ Jiff เป็นฐานที่เสถียรของ public API ได้
- แม้หลังจาก Jiff 1.0 ออกแล้ว Jiff 0.2 ยังมีแผนได้รับอัปเดตแก้บั๊กสำคัญเป็นเวลา 1 ปี
- ไม่มีการพัฒนาฟีเจอร์ใหม่แบบ active
- เป็นแผนเพื่อให้ช่วงผ่อนผันในการย้ายเวอร์ชัน เนื่องจากมีผู้ใช้ Jiff 0.2 อยู่แล้วจำนวนมาก
ประสิทธิภาพและเส้นทางฟอร์แมตขั้นสูง
- เป้าหมายการออกแบบที่สำคัญที่สุดคือการเป็น ไลบรารีวันที่และเวลาระดับสูง ที่ใช้งานผิดได้ยาก
- ประสิทธิภาพเป็นเป้าหมายลำดับที่สอง โดยมุ่งให้มีประสิทธิภาพที่สมเหตุสมผล แต่อาจยังมีบางส่วนที่ปรับปรุงได้
- benchmark อยู่ในไดเรกทอรี
bench - บางส่วนได้รับการ optimize แล้ว แต่ยังมีอีกหลายส่วนที่ยังไม่ได้ optimize
- การปรับปรุงประสิทธิภาพเป็นเป้าหมาย แต่โดยทั่วไป ความเข้าใจได้ของ API และความถูกต้องจะมาก่อนประสิทธิภาพ
- โมดูลย่อยของ Jiff โดยเฉพาะ
jiff::fmtทำหน้าที่เป็นทางออกสำหรับ API ที่ซับซ้อนซึ่งต้องการการควบคุมมากขึ้น- การ implement
std::fmt::DisplayของZonedอาจทำให้เขียนลงในบัฟเฟอร์ที่นำกลับมาใช้ซ้ำได้ยาก jiff::fmt::temporal::DateTimePrinter::print_zonedช่วยให้เขียนZonedลงในStringหรือVec<u8>ที่มีอยู่แล้วได้
- การ implement
การจัดการเขตเวลาตามแพลตฟอร์ม
- ปัญหาการรองรับแพลตฟอร์มของไลบรารีวันที่และเวลาส่วนใหญ่เกี่ยวข้องกับ การรองรับเขตเวลา
- การปฏิสัมพันธ์กับแพลตฟอร์มที่ Jiff จัดการ
- วิธีค้นหาข้อมูลการเปลี่ยนเวลาของตัวระบุเขตเวลา IANA เช่น
Antarctica/Troll - วิธีค้นหาเขตเวลาเริ่มต้นของระบบปัจจุบัน
- วิธีค้นหาข้อมูลการเปลี่ยนเวลาของตัวระบุเขตเวลา IANA เช่น
- ข้อมูลการเปลี่ยนเขตเวลาอาศัย IANA Time Zone Database
- บน Unix โดยทั่วไปจะใช้
/usr/share/zoneinfoและทำตามการตั้งค่าตัวแปรสภาพแวดล้อมTZDIRด้วย - บน Windows จะฝังสำเนา Time Zone Database ไว้ในไลบรารีที่คอมไพล์แล้วโดยอัตโนมัติ
- วิธีตรวจจับเขตเวลาของระบบ
- บน Unix อ่าน
/etc/localtime - บน Windows อ่านตัวระบุเขตเวลาเฉพาะของ Windows ด้วย
GetDynamicTimeZoneInformationแล้วแมปเป็นตัวระบุเขตเวลา IANA ผ่าน CLDR XML data ของ Unicode
- บน Unix อ่าน
- คาดว่าการรองรับแพลตฟอร์มอื่นจะเพิ่มขึ้นเมื่อเวลาผ่านไป แต่แพลตฟอร์มหายากที่ทดสอบได้ยากมีแนวโน้มต้องพึ่งพา pull request จาก contributor
นโยบาย dependency และ MSRV
- การที่ Jiff มี 0 dependency บน Unix เป็นการออกแบบโดยตั้งใจ
- เกณฑ์การเพิ่ม dependency ใหม่ให้ Jiff ซึ่งเป็น crate ใน ecosystem นั้นค่อนข้างอนุรักษนิยม
- เมื่อจำเป็นจริง ๆ เพื่อปฏิสัมพันธ์กับแพลตฟอร์ม
- เมื่อจำเป็นต่อการทำงานร่วมกัน เช่น
serde
- dependency เพื่อวัตถุประสงค์ด้าน interoperability ก็ถูกพิจารณาอย่างอนุรักษนิยมเช่นกัน โดยทั่วไปพยายามพึ่งพาเฉพาะสิ่งที่มีการปล่อย breaking change น้อยกว่า Jiff
- หากแยก Jiff ออกเป็นหลาย crate อาจมี dependency ใหม่เกิดขึ้นได้ แต่ปัจจุบันยังไม่มีแผน
- มีแนวทางให้คงจำนวน crate ไว้น้อย โดยระบุจากประสบการณ์ว่าการจัดการขอบเขต semver API จำนวนมากมี overhead ด้านการบำรุงรักษาสูง
- เวอร์ชันคอมไพเลอร์ Rust ขั้นต่ำที่ Jiff รองรับคือ MSRV 1.70.0
- ตัว Jiff เองและ dependency ของ Jiff ภายใน repository จะไม่ใช้เวอร์ชัน Rust ที่ต้องการคอมไพเลอร์ Rust ซึ่งปล่อยภายใน 1 ปีก่อนหน้า
- crate ที่อยู่ใน repository และพึ่งพา Jiff เช่น
jiff-icuอาจใช้ MSRV ที่ใหม่กว่าได้ แต่จะไม่กำหนดให้ต้องใช้ MSRV ใหม่กว่า crate เป้าหมายที่ต้อง integrate ด้วย - MSRV ของ dependency ภายนอก เช่น
windows-sys,portable-atomicอยู่นอกเหนือการควบคุมของ Jiff - ตามธรรมเนียมของ ecosystem Rust, Jiff ไม่ถือว่าการเพิ่ม MSRV เป็นการเปลี่ยนแปลงที่ไม่เข้ากันกับ semver แต่จะจำกัดการเพิ่ม MSRV ไว้ในการอัปเดต minor version เท่านั้น
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
โดยรวมดูดี แต่ติดใจเรื่อง ไวยากรณ์ ToSpan นิดหน่อย
let span = 5.days().hours(8).minutes(1);การที่มีแค่ตัวเลขตัวแรกอยู่ข้างหน้า แล้วที่เหลือเข้าไปเป็นอาร์กิวเมนต์ของฟังก์ชัน รู้สึกแปลก ๆ
ถ้าไม่ชอบก็เขียนแบบ
let span = Span::new().days(5).hours(8).minutes(1);ได้ ซึ่งก็แค่เพิ่มตัวอักษรอีกนิดหน่อย เลยไม่ได้แย่นักuse jiff::{Timestamp, ToSpan};แล้วตามด้วย"2024-07-11T01:14:00Z".parse()?ที่ถูกพาร์สเป็น Timestamp ตรงนี้ทำให้สะดุดเหมือนกันจำได้ว่า Rust ใช้อะไรคล้ายอินเทอร์เฟซแทนคลาส แต่พอนำเข้าไลบรารีแล้วจู่ ๆ สตริงก็มีเมธอด
parse()เพิ่มขึ้นมา แถมเมธอดชื่อทั่วไปแบบนั้นกลับสร้างอ็อบเจ็กต์Timestampได้ เลยสงสัยว่าทำไมถึงเป็นแบบนั้นความหมายของ
str.parse()ถูกกำหนดโดยชนิดทางซ้ายหรือเปล่า แล้วถ้าไลบรารีวันที่กับไลบรารี S-expression ของ Lisp ต่างก็เพิ่มparse()ให้กับสตริง จะเกิดอะไรขึ้นก็สงสัยเหมือนกันเลยมีคำถามต่อไปอีกว่าทำไมไม่ใช้ไวยากรณ์แบบ
Timestamp.parse(str)let span = 5.days() + 8.hours() + 1.minutes();มากกว่าไวยากรณ์เดิมดูเหมือนรูปแบบที่ Ruby น่าจะใช้
เวลาอ่านโค้ด ถ้าเห็นก่อนว่ากำลัง จัดการ span อยู่ก็น่าจะดีกว่า
let span = Span::days(5).hours(8).minutes(1);ก็ดูน่าจะดีกว่าเห็นคนจำนวนมาก ประเมินความซับซ้อน ของไลบรารีวันที่/เวลาต่ำเกินไป
มักจะพูดกันว่า “ใช้ UTC/Unix time เป็นตัวแทนภายในก็พอ”, “ช่วงเวลาก็แทนด้วยนาโนวินาทีไปเลย”, “ใช้แค่ออฟเซ็ตแทน time zone ก็พอ”
ถ้าคิดแบบนั้น แนะนำให้อ่านเอกสารการออกแบบของ Jiff: https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
สมกับเป็นงานของ BurntSushi ทั้งยอดเยี่ยมและละเอียดมาก
ส่วนการเปรียบเทียบกับ chrono ซึ่งเป็นไลบรารีวันที่/เวลามาตรฐานโดยพฤตินัยของ Rust ก็อ่านคุ้มเช่นกัน: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
องค์ประกอบอย่างการคำนวณเวลา DST ที่ยังถูกต้องแม้ผ่านการ serialize/deserialize, ช่วงเวลาที่ปัดเศษได้, การคำนวณปฏิทินที่รับรู้ time zone, และการตรวจจับความขัดแย้งของ time zone ในอดีต ทำให้ไลบรารีนี้ทั้งแม่นยำ มีประโยชน์ และใช้งานสะดวก
chrono เป็นไลบรารีที่ครอบคลุมและ “ถูกต้อง” แต่ค่อนข้างแข็งทื่อและไม่ได้ใช้ง่ายนัก
ใช้ ripgrep มาตั้งแต่ก่อนที่ Debian จะมี
rgมาให้เป็นค่าเริ่มต้น และก็เคยใช้ JodaTime ตั้งแต่สมัยที่ยังมีคนคิดว่า Eclipse ดีกว่า IntelliJ IDEAแต่ในเอกสารนั้นก็ไม่มีตรงไหนที่หักล้างคำพูดว่า “ช่วงเวลาแทนด้วยนาโนวินาทีก็พอ”
ผู้ใช้จำเป็นต้องเห็นเวลาที่ถูกต้องตาม time zone และ DST แต่ตัวโปรแกรมมักไม่จำเป็น
ถ้าไม่ได้ทำงานที่ต้องจัดการหลาย time zone โดยตรง การแทนช่วงเวลาด้วยมิลลิวินาที/นาโนวินาทีก็มักปลอดภัยมากอยู่แล้ว
ต่อให้มนุษย์สร้าง time zone กับ DST ขึ้นมา ก็ไม่ได้เปลี่ยนความจริงทางฟิสิกส์ที่นาฬิกาภายใน CPU ยังเดินหลายพันล้านครั้งต่อวินาที
แค่ดูเคอร์เนลระบบปฏิบัติการที่เมื่อไม่กี่วันก่อนก็ไม่ได้พังไปครึ่งโลก จะเห็นว่าโค้ด timeout จำนวนมากยังแทนค่าเป็นมิลลิวินาที
ไม่อย่างนั้นอาจเข้าใจผิดว่าการทำ “คูลดาวน์ 30 วินาที” ต้องเอา 30 วินาทีไปบวกกับเวลาปัจจุบันตาม time zone, เก็บเป็นสตริงที่รวมทั้ง time zone, DST และรูปแบบ 12/24 ชั่วโมง แล้วค่อยตรวจสอบ leap second อีกที
ทั้งที่จริงใช้ timeout/คูลดาวน์ 30 วินาที ที่แทนด้วยมิลลิวินาทีไปตรง ๆ ก็ได้ และต่อให้มันเกิดขึ้นหลังจากนั้น 29 วินาทีในมุมมองของผู้ใช้ ก็ไม่ต้องกังวลเรื่อง leap second
ดูเป็นไลบรารีที่เจ๋งดี
สงสัยว่าเหตุใด BurntSushi ถึงสร้างไลบรารีใหม่ขึ้นมา
ไม่ค่อยได้ทำงานกับการจัดการเวลาใน Rust มากนัก เลยอยากรู้ว่าเป็นเพราะไลบรารีเดิมมีปัญหาด้านประสิทธิภาพ, API เดิมใช้งานลำบาก, หรือแค่ทำเพื่อความสนุก หรือมีเหตุผลอื่น
implementation ของไลบรารีมาตรฐาน Java ไม่ค่อยดีนัก และเพื่อแก้ปัญหานั้นจึงมี JodaTime ออกมา
ต่อมาใน Java 8 ก็มี DateTime API ใหม่ที่ได้รับอิทธิพลจาก JodaTime อย่างมาก และเพราะอยู่ในไลบรารีมาตรฐาน จึงทำให้ผู้เขียนไลบรารีต่าง ๆ นำไปใช้กันได้กว้างขวางกว่า
https://www.joda.org/joda-time/
https://www.baeldung.com/java-8-date-time-intro
https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
https://github.com/BurntSushi/jiff/blob/master/COMPARE.md
สรุปคือ ส่วนใหญ่เป็นเรื่องของ API และ การรองรับเขตเวลา IANA
สถานะของ ไลบรารีปฏิทิน ใน Rust ยังไม่ค่อยน่าพอใจนัก
ใน Pandas มีทั้ง
.tz_convert()และ.tz_localize()และเรื่องการแปลงเขตเวลาก็แทบจะจบได้ด้วยสองอย่างนั้นงานที่ใช้เป็นตัวอ้างอิงคือ “หาค่าเวลาแรกของวันตาม CET/CEST สำหรับวันที่กำหนดในรูป UTC” ซึ่งใน Pandas ทำได้ง่ายมาก
แต่ใน Chrono ต้องสร้าง
NaiveDateแล้วแปลงเป็นDateTimeจากนั้นก็แปลงเป็นDateTimeอีกที และยังหาแพตเทิร์นที่สม่ำเสมอของการแปลงพวกนี้ไม่เจอบางครั้งเป็นเมธอดของสมาชิก บางครั้งก็เป็นเมธอดแบบสแตติกของอ็อบเจ็กต์เขตเวลา
หวังว่าสักวันจะมีคนมาจัดการให้ถูกเสียที Jiff ดูเหมือนเป็นก้าวหนึ่งไปในทิศทางที่ถูกต้อง แต่ไวยากรณ์บางครั้งก็ดูแปลก ๆ เลยอยากให้มันมีรูปแบบที่คาดเดาได้มากกว่านี้
date(y, m, d).intz("Europe/Rome")?ถ้าต้องการ UTC จากตรงนั้น ก็เพิ่ม
with_time_zone(TimeZone::UTC)ได้เลยอยากให้ช่วยอธิบายเพิ่มเติมว่า Jiff จะทำให้ดีขึ้นได้อย่างไร หรือส่วนที่ว่ารูปแบบไวยากรณ์ดูแปลกหมายถึงอะไร
“ที่รัก ตื่นได้แล้ว มี BurntSushi ตัวใหม่มาแล้ว”[0]
เอาจริง ๆ คือสงสัยว่ามีใครในกลุ่มผู้ใช้ Rust ที่นี่รู้ไหมว่าทำไม crate นี้ถึงไม่ใช้
tracingอะไรทำนองนั้นอาจเพราะมันหนักเกินไปก็ได้ ขนาดของ crate แทบจะประมาณครึ่งหนึ่งเลย
แน่นอนว่า
logก็โอเคอยู่แล้ว และก็ไม่แน่ใจว่าการ trace ไปถึงระดับการเรียกใช้งานการคำนวณเขตเวลานั้นเป็น use case ที่พบได้ทั่วไปหรือเปล่า แต่ก็สงสัยว่ามีเหตุผลพิเศษอะไรหรือไม่[0] https://knowyourmeme.com/memes/wake-up-babe
logใกล้เคียงกับ ตัวหารร่วมต่ำสุด มากกว่าแถมยังทำงานร่วมกับ
tracingได้ดี ดังนั้นนั่นน่าจะเป็นเหตุผลที่ Jiff ใช้มันอีกอย่างคือเป็นสิ่งที่ใช้ต่อเนื่องมาตั้งแต่ยุคแรก ๆ ของ crates.io
Jiff ไม่ได้ต้องการอะไรมากไปกว่าการส่งข้อความออกมาตามระดับล็อกที่กำหนด
แน่นอนว่า
tracingก็น่าจะทำงานได้ดีเหมือนกันBurntSushi เองก็เป็นคนที่สร้าง ecosystem ของ regex ใน Rust ขึ้นมาทั้งชุดด้วย
ไม่ว่าจะเป็น Rust หรือ ecosystem อื่น ๆ สิ่งที่น่าเสียดายที่สุดในไลบรารีเวลาเดิม ๆ คือการ รองรับ leap second ที่ไม่ดีพอ
โดยมากเป็นเพราะภายในใช้ UNIX timestamp แทน TAI และน่าเสียดายที่ไลบรารีนี้ก็ไม่ต่างกัน
ดูเหมือนจะมีวิธีรองรับได้บ้างผ่านไฟล์ tzif แต่ก็ยังไม่ใช่การรองรับแบบ first-class
มีรายละเอียดเพิ่มเติมใน issue ของ Jiff นี้: https://github.com/BurntSushi/jiff/issues/7
UNIX timestamp ไม่ได้ใช้คำนิยามวินาทีแบบ SI แต่ใช้ 1/86000 ของวันปัจจุบันแทน ดังนั้นความยาวของทุกวินาทีแบบ UNIX จึงไม่เท่ากัน และทำให้การคำนวณช่วงเวลาอย่างถูกต้องพังไป
เข้าใจได้ว่ามันเป็นการประนีประนอมเพื่อสืบทอดความเข้ากันได้กับวิธีติดตามเวลาแบบเก่า และเพื่อให้การฟอร์แมตปฏิทินทำได้เร็ว แต่ไม่คิดว่านี่เป็นการประนีประนอมที่ถูกต้อง
UNIX timestamp เอาประเด็นด้านการแสดงผลมาปะปนกับข้อมูลเสียเอง
มองว่า leap second ควรถูกจัดการแบบเดียวกับวันที่ 29 กุมภาพันธ์หรือเขตเวลาอย่างเป๊ะ ๆ
hifitimeถึงไม่เหมาะทุกครั้งที่มีการพูดถึง leap second ก็มักจะไหลไปเป็นการคุยเชิงนามธรรมเสียมากกว่า
แทบไม่ค่อยเชื่อมโยงกับ use case ในโลกจริงเลย
สำหรับ use case ทางวิทยาศาสตร์นั้นเข้าใจได้ และคิดว่าไลบรารีเฉพาะทางก็รองรับงานแบบนั้นได้ดีอยู่แล้ว
นอกเหนือจากนั้นก็ยังไม่แน่ใจว่ามีความจำเป็นมากแค่ไหน
Jiffออกเสียงเป็น “Giff” โดยใช้ G แข็งgoหรือแบบในgin?“Jiff ออกเสียงเป็น
gifที่ใช้ g แบบนุ่มเหมือนในgem”ไม่มีทาง!
ฉันขออยู่กับ chrono ต่อไป †
† แน่นอนว่าออกเสียงเป็น “trono” โดยใช้
chแบบในchaseดังนั้นออกเสียงว่า jiff หรือออกเสียงว่า gif?
“Jiff ออกเสียงเป็น
gifที่ใช้เสียง g แบบนุ่มเหมือนในgem”อ้อ เข้าใจแล้วว่าเล่นมุกอะไร…
ตามที่ผู้สร้างบอก GIF ออกเสียงว่า “jif” มาตลอด ดังนั้นถ้าอยากเลี่ยงความสับสน ก็น่าจะดีถ้าผู้สร้างเครื่องมือตัวใหม่นี้ออกเสียง Jiff ว่า “gif”