date-fns’e Hızlı Bir Bakış: Basit Bir JavaScript Tarih Kütüphanesi
JavaScript, web geliştirmenin temel taşlarından biridir ve modern uygulamaların büyük bir çoğunluğunda kullanılır. Ancak JavaScript’in yerleşik Date nesnesi, tarih ve saat işlemleri konusunda geliştiricilere yeterince esneklik ve kolaylık sunmaz. Tarihlerin biçimlendirilmesi, karşılaştırılması, manipülasyonu veya farklı zaman dilimleriyle çalışmak gibi yaygın görevler, Date nesnesiyle doğrudan uğraşırken karmaşık ve hataya açık hale gelebilir. Bu durum, Moment.js gibi popüler kütüphanelerin ortaya çıkmasına neden olmuştur. Ancak Moment.js’in boyut ve değiştirilebilirlik (mutability) sorunları, daha modern ve hafif alternatiflerin aranmasına yol açmıştır. İşte tam bu noktada, date-fns devreye girer.
date-fns, modern JavaScript uygulamaları için tasarlanmış, kapsamlı ama hafif bir tarih yardımcı kütüphanesidir. Fonksiyonel programlama prensiplerini benimseyen, değiştirilemez (immutable) ve modüler yapısıyla öne çıkar. Bu makalede, date-fns‘in temel özelliklerine, kullanımına ve onu diğer kütüphanelerden ayıran önemli noktalara derinlemesine bir bakış atacağız. Amacımız, geliştiricilere date-fns‘in gücünü ve sadeliğini göstererek, tarih ve saat işlemlerini ne kadar kolaylaştırabileceğini anlatmaktır.
date-fns Neden Gereklidir? JavaScript’in Date Nesnesiyle Mücadele
JavaScript’in Date nesnesi, temel tarih ve saat işlemlerini gerçekleştirmek için yeterli olsa da, gerçek dünya uygulamalarında karşılaşılan karmaşık senaryolarda yetersiz kalır. Örneğin, bir tarihi belirli bir formata göre biçimlendirmek, iki tarih arasındaki farkı bulmak, bir tarihe gün, ay veya yıl eklemek/çıkarmak gibi işlemler, Date nesnesinin metodlarıyla doğrudan yapılamaz veya çok uzun ve okunaksız kodlar gerektirir.
new Date() ile oluşturulan bir tarih nesnesine setMonth() gibi metotlar uygulandığında, orijinal nesne üzerinde değişiklik yapılır (mutable). Bu durum, özellikle büyük projelerde veya eşzamanlı işlemlerde beklenmedik yan etkilere ve hatalara yol açabilir. Ayrıca, Date nesnesinin farklı tarayıcılarda veya Node.js ortamlarında farklı davranışlar sergileyebilmesi, geliştiriciler için başka bir baş ağrısı kaynağıdır.
Moment.js gibi kütüphaneler bu sorunlara çözüm sunmuş olsa da, genellikle büyük bir boyutla gelirler ve kullanılmayan birçok fonksiyonu da pakete dahil ederler. Bu durum, özellikle mobil cihazlar veya düşük bant genişliğine sahip kullanıcılar için uygulamanın yüklenme süresini artırabilir. İşte date-fns, bu zorlukları aşmak için modern bir yaklaşım sunar.
date-fns’in Temel Felsefesi ve Avantajları
date-fns, tasarımında birkaç temel prensibi benimsemiştir:
* Değiştirilemezlik (Immutability): date-fns‘teki tüm fonksiyonlar, orijinal Date nesnesini değiştirmez. Bunun yerine, her zaman yeni bir Date nesnesi döndürürler. Bu, kodunuzu daha öngörülebilir ve hatasız hale getirir. Fonksiyonel programlama prensiplerine uygun bu yaklaşım, özellikle React, Vue gibi modern framework’lerle çalışırken veri akışını yönetmeyi kolaylaştırır.
* Modülerlik ve Ağaç Budama (Tree-shaking): date-fns, her biri kendi başına çalışan yüzlerce küçük fonksiyondan oluşur. Bu sayede, uygulamanızda sadece ihtiyacınız olan fonksiyonları içe aktarabilirsiniz. Modern derleyiciler (Webpack, Rollup gibi) “ağaç budama” (tree-shaking) özelliği sayesinde kullanılmayan kodları paketinizden atarak nihai dosya boyutunu önemli ölçüde küçültür. Bu, uygulamanızın daha hızlı yüklenmesini sağlar.
* Yerel Date Nesnesini Kullanma: date-fns, kendi özel bir tarih nesnesi oluşturmak yerine, doğrudan JavaScript’in yerleşik Date nesnesiyle çalışır. Bu, öğrenme eğrisini düşürür ve diğer kütüphanelerle veya yerel JavaScript koduyla entegrasyonu kolaylaştırır. Ayrıca, Date nesnesinin performans optimizasyonlarından ve tarayıcı implementasyonlarından faydalanır.
* Saf Fonksiyonlar (Pure Functions): Tüm date-fns fonksiyonları saf fonksiyonlardır. Yani, aynı girdilerle her zaman aynı çıktıyı üretirler ve dışarıdan herhangi bir durumu değiştirmezler. Bu, test edilebilirliği artırır ve kodunuzu daha güvenilir hale getirir.
* TypeScript Desteği: date-fns, TypeScript ile tam uyumludur ve mükemmel tip tanımlamaları sunar. Bu, özellikle büyük ölçekli projelerde geliştirme sürecini hızlandırır ve potansiyel hataları derleme zamanında yakalamanıza yardımcı olur.
* Uluslararasılaştırma (i18n): Kütüphane, çeşitli diller ve yerel ayarlarla (locale) çalışmayı destekler. Biçimlendirme veya göreceli zaman ifadeleri gibi işlemlerde farklı yerel ayarları kolayca kullanabilirsiniz.
Başlangıç: Kurulum ve Temel Kullanım
date-fns‘i projenize dahil etmek oldukça basittir. npm veya yarn kullanarak kurabilirsiniz:
npm install date-fns
veya
yarn add date-fns
Kurulum tamamlandıktan sonra, ihtiyacınız olan fonksiyonları doğrudan içe aktararak kullanmaya başlayabilirsiniz. Örneğin, bir tarihi biçimlendirmek için format fonksiyonunu kullanabiliriz:
import { format } from 'date-fns';
const now = new Date(); // Şu anki tarih ve saat
const formattedDate = format(now, 'dd/MM/yyyy'); // "25/10/2023" gibi bir çıktı
console.log(formattedDate);
const formattedTime = format(now, 'HH:mm:ss'); // "14:35:00" gibi bir çıktı
console.log(formattedTime);
Bu örnekte görüldüğü gibi, date-fns fonksiyonları genellikle bir Date nesnesi alır ve ardından belirli bir işlem yapar. Bu sadelik, kütüphanenin temel çekiciliğidir.
Temel Fonksiyon Kategorileri ve Örnekler
date-fns, tarih ve saatlerle ilgili neredeyse her türlü ihtiyacı karşılayacak zengin bir fonksiyon setine sahiptir. Bu fonksiyonları ana kategorilere ayırarak inceleyelim:
1. Biçimlendirme (Formatting)
Tarihleri insan tarafından okunabilir stringlere dönüştürmek en yaygın işlemlerden biridir. date-fns bu konuda oldukça esnektir.
* format(date, formatString): En sık kullanılan fonksiyondur. Bir Date nesnesini, verilen biçim stringine göre biçimlendirir. Biçim stringleri Moment.js’e benzerdir (yyyy yıl, MM ay, dd gün, HH saat, mm dakika, ss saniye vb.).
import { format } from 'date-fns';
const myDate = new Date(2023, 9, 25, 15, 30, 45); // 25 Ekim 2023, 15:30:45
console.log(format(myDate, 'dd MMMM yyyy, HH:mm:ss'));
// Çıktı: "25 October 2023, 15:30:45" (Varsayılan İngilizce locale ile)
console.log(format(myDate, 'EEEE, do MMMM yyyy'));
// Çıktı: "Wednesday, 25th October 2023"
* formatDistance(date, baseDate, options): İki tarih arasındaki mesafeyi “X gün önce”, “yaklaşık 2 ay sonra” gibi göreceli bir şekilde biçimlendirir.
import { formatDistance, subDays } from 'date-fns';
const today = new Date();
const twoDaysAgo = subDays(today, 2); // İki gün önceki tarih
console.log(formatDistance(twoDaysAgo, today));
// Çıktı: "2 days ago"
* formatRelative(date, baseDate, options): Bir tarihi, referans bir tarihe göre göreceli olarak biçimlendirir (“bugün saat 10:00”, “yarın”, “geçen hafta Salı” gibi).
import { formatRelative, subHours } from 'date-fns';
const today = new Date();
const threeHoursAgo = subHours(today, 3);
console.log(formatRelative(threeHoursAgo, today));
// Çıktı: "today at 11:30 AM" (Saat değişebilir)
2. Ayrıştırma (Parsing)
String formatındaki tarihleri Date nesnelerine dönüştürmek için kullanılır.
* parse(dateString, formatString, referenceDate): Belirli bir format stringine uyan bir tarih stringini ayrıştırır. referenceDate genellikle ayrıştırma sırasında eksik olan tarih parçalarını (örneğin sadece saat verildiğinde gün, ay, yıl) tamamlamak için kullanılır.
import { parse } from 'date-fns';
const dateString = '25.10.2023 10:30';
const formatStr = 'dd.MM.yyyy HH:mm';
const parsedDate = parse(dateString, formatStr, new Date()); // new Date() eksik parçalar için referans
console.log(parsedDate); // Date nesnesi çıktısı
* parseISO(isoString): ISO 8601 formatındaki bir stringi (örneğin “2023-10-25T14:30:00.000Z”) ayrıştırır.
import { parseISO } from 'date-fns';
const isoString = '2023-10-25T14:30:00.000Z';
const parsedIsoDate = parseISO(isoString);
console.log(parsedIsoDate); // Date nesnesi çıktısı
3. Manipülasyon (Manipulation)
Bir tarihe belirli bir zaman birimi eklemek veya çıkarmak için kullanılır. Tüm bu fonksiyonlar değiştirilemezdir (immutable), yani yeni bir Date nesnesi döndürürler.
* addYears(date, amount), addMonths(date, amount), addWeeks(date, amount), addDays(date, amount), addHours(date, amount), addMinutes(date, amount), addSeconds(date, amount): Bir tarihe belirtilen miktarda zaman birimi ekler.
import { addDays, addHours } from 'date-fns';
const today = new Date();
const tomorrow = addDays(today, 1);
const inTwoHours = addHours(today, 2);
console.log(tomorrow);
console.log(inTwoHours);
* subYears(date, amount), subMonths(date, amount), vb.: Bir tarihten belirtilen miktarda zaman birimi çıkarır.
import { subMonths, subWeeks } from 'date-fns';
const now = new Date();
const lastMonth = subMonths(now, 1);
const lastWeek = subWeeks(now, 1);
console.log(lastMonth);
console.log(lastWeek);
* startOfDay(date), endOfDay(date), startOfWeek(date, options), endOfWeek(date, options), startOfMonth(date), endOfMonth(date), startOfYear(date), endOfYear(date): Bir tarihin başlangıcını veya bitişini döndürür. Haftanın başlangıcı için weekStartsOn seçeneği ile haftanın hangi gün başladığını belirtebilirsiniz (örneğin Pazar için 0, Pazartesi için 1).
import { startOfDay, endOfMonth } from 'date-fns';
const someDate = new Date(2023, 9, 15, 10, 30); // 15 Ekim 2023, 10:30
const startOfToday = startOfDay(someDate);
const endOfTheMonth = endOfMonth(someDate);
console.log(startOfToday); // 15 Ekim 2023, 00:00:00
console.log(endOfTheMonth); // 31 Ekim 2023, 23:59:59.999
4. Karşılaştırma ve Fark (Comparison & Difference)
İki tarih arasındaki ilişkiyi veya farkı bulmak için kullanılır.
* isBefore(date, dateToCompare), isAfter(date, dateToCompare), isEqual(date, dateToCompare): Bir tarihin diğerinden önce mi, sonra mı olduğunu veya eşit mi olduğunu kontrol eder.
import { isBefore, isAfter, isEqual } from 'date-fns';
const date1 = new Date(2023, 9, 25);
const date2 = new Date(2023, 9, 26);
const date3 = new Date(2023, 9, 25);
console.log(isBefore(date1, date2)); // true
console.log(isAfter(date2, date1)); // true
console.log(isEqual(date1, date3)); // true
* differenceInDays(dateLeft, dateRight), differenceInHours(dateLeft, dateRight), differenceInMinutes(dateLeft, dateRight), vb.: İki tarih arasındaki farkı belirtilen birim cinsinden döndürür.
import { differenceInDays, differenceInHours } from 'date-fns';
const startDate = new Date(2023, 9, 20);
const endDate = new Date(2023, 9, 25);
console.log(differenceInDays(endDate, startDate)); // 5
console.log(differenceInHours(endDate, startDate)); // 120 (5 * 24)
* isSameDay(date1, date2), isSameMonth(date1, date2), isSameYear(date1, date2): İki tarihin aynı gün, ay veya yıl içinde olup olmadığını kontrol eder.
import { isSameDay } from 'date-fns';
const dateA = new Date(2023, 9, 25, 10, 0);
const dateB = new Date(2023, 9, 25, 15, 30);
console.log(isSameDay(dateA, dateB)); // true
5. Yardımcı Fonksiyonlar (Utility Functions)
Çeşitli genel amaçlı tarih ve saat işlemleri için kullanılır.
* getYear(date), getMonth(date), getDate(date), getHours(date), getMinutes(date), getSeconds(date): Bir Date nesnesinden belirli bir zaman birimini alır. getMonth 0’dan başlar (Ocak 0’dır).
import { getYear, getMonth, getDate } from 'date-fns';
const myDate = new Date(2023, 9, 25); // 25 Ekim 2023
console.log(getYear(myDate)); // 2023
console.log(getMonth(myDate)); // 9 (Ekim)
console.log(getDate(myDate)); // 25
* isValid(date): Bir Date nesnesinin geçerli olup olmadığını kontrol eder.
import { isValid } from 'date-fns';
console.log(isValid(new Date('2023-10-25'))); // true
console.log(isValid(new Date('invalid-date'))); // false
* toDate(argument): Çeşitli girdileri (sayı, string, başka bir Date nesnesi) bir Date nesnesine dönüştürmeye çalışır.
import { toDate } from 'date-fns';
console.log(toDate(1678886400000)); // Timestamp'ten Date
console.log(toDate('2023-10-25')); // String'ten Date (ISO formatını varsayar)
* eachDayOfInterval(interval, options): Belirtilen bir zaman aralığındaki her günü içeren bir Date nesneleri dizisi döndürür.
import { eachDayOfInterval } from 'date-fns';
const result = eachDayOfInterval({
start: new Date(2023, 9, 20),
end: new Date(2023, 9, 25)
});
console.log(result); // [20 Ekim, 21 Ekim, ..., 25 Ekim] Date nesneleri dizisi
Uluslararasılaştırma (i18n)
date-fns, farklı dillerdeki tarih ve saat biçimlendirme ihtiyaçlarını karşılamak için güçlü bir uluslararasılaştırma (i18n) desteği sunar. format, formatDistance, formatRelative gibi fonksiyonlara bir locale nesnesi geçirerek çıktının dilini değiştirebilirsiniz.
import { format, formatDistance } from 'date-fns';
import { tr } from 'date-fns/locale'; // Türkçe locale'i içe aktar
const myDate = new Date(2023, 9, 25, 15, 30, 45); // 25 Ekim 2023, 15:30:45
const today = new Date();
const twoDaysAgo = new Date(2023, 9, 23);
console.log(format(myDate, 'dd MMMM yyyy, EEEE', { locale: tr }));
// Çıktı: "25 Ekim 2023, Çarşamba"
console.log(formatDistance(twoDaysAgo, today, { locale: tr, addSuffix: true }));
// Çıktı: "2 gün önce"
Bu özellik, küresel uygulamalar geliştirirken büyük kolaylık sağlar ve kullanıcı deneyimini iyileştirir.
Gelişmiş Konular ve En İyi Uygulamalar
* Zaman Dilimleri (Time Zones): date-fns, JavaScript’in yerel Date nesnesiyle çalıştığı için, doğrudan zaman dilimi manipülasyonu yapmaz. Date nesnesi, tarayıcının veya Node.js ortamının yerel zaman dilimini kullanır. Eğer sunucu tarafında veya farklı zaman dilimlerinde karmaşık işlemler yapmanız gerekiyorsa, date-fns‘i date-fns-tz gibi özel bir eklentiyle veya Intl.DateTimeFormat gibi yerel Web API’leriyle birlikte kullanmanız gerekebilir. date-fns-tz kütüphanesi, date-fns fonksiyonlarının zaman dilimi farkındalığıyla çalışmasını sağlayan bir köprü görevi görür.
* TypeScript Entegrasyonu: date-fns‘in TypeScript desteği mükemmeldir. Fonksiyonların tipleri, parametreleri ve dönüş değerleri doğru bir şekilde tanımlanmıştır. Bu, geliştirme sırasında otomatik tamamlama, tip kontrolü ve hata ayıklama süreçlerini büyük ölçüde kolaylaştırır.
* Performans ve Ağaç Budama: Daha önce de belirtildiği gibi, date-fns‘in modüler yapısı, uygulamanızın nihai paket boyutunu minimumda tutar. Sadece ihtiyacınız olan fonksiyonları içe aktararak, gereksiz kodların uygulamanıza dahil edilmesini önlersiniz. Bu, özellikle performans kritik uygulamalar veya mobil web siteleri için çok önemlidir.
// Kötü pratik: Tüm kütüphaneyi içe aktarmak (ağaç budamayı engeller)
// import * as dateFns from 'date-fns';
// İyi pratik: Sadece ihtiyacınız olan fonksiyonları içe aktarmak
import { format, addDays } from 'date-fns';
* Moment.js ve Day.js ile Karşılaştırma:
* Moment.js: Uzun yıllar boyunca standart olmuştur ancak büyük boyutu, değiştirilebilir yapısı ve artık aktif olarak geliştirilmiyor oluşu nedeniyle yerini yeni nesil kütüphanelere bırakmaktadır.
* Day.js: Moment.js’e benzer bir API sunan, ancak çok daha hafif bir alternatiftir. Boyut ve performans açısından date-fns ile rekabet eder. Ancak date-fns, saf fonksiyonel yaklaşımı ve yerel Date nesnesiyle çalışma prensibiyle ayrışır. Day.js’in API’si Moment.js’e daha yakınken, date-fns daha “JavaScript-native” bir his verir.
* date-fns: Değiştirilemezlik, modülerlik ve saf fonksiyonlar üzerine kurulu modern bir yaklaşıma sahiptir. En küçük paket boyutunu hedefler ve TypeScript desteği mükemmeldir. Fonksiyonel programlama paradigmasını benimseyen geliştiriciler için idealdir.
Sonuç
date-fns, JavaScript’te tarih ve saat işlemleriyle uğraşan geliştiriciler için güçlü, esnek ve modern bir çözümdür. Yerleşik Date nesnesinin sınırlamalarını aşarken, Moment.js gibi eski kütüphanelerin getirdiği dezavantajlardan kaçınır. Değiştirilemez yapısı, modüler mimarisi, ağaç budama dostu tasarımı ve mükemmel TypeScript desteği ile date-fns, modern web uygulamalarının performans ve sürdürülebilirlik gereksinimlerini karşılar.
Eğer projenizde tarih ve saatlerle sıkça çalışıyor, kodunuzun öngörülebilir ve bakımı kolay olmasını istiyor, aynı zamanda uygulama boyutunu düşük tutmayı hedefliyorsanız, date-fns sizin için doğru seçim olabilir. Kütüphanenin geniş fonksiyon yelpazesi, basit ve tutarlı API’si sayesinde, tarihle ilgili karmaşık görevleri bile şaşırtıcı bir kolaylıkla yerine getirebilirsiniz. date-fns ile tanışmak, JavaScript’teki tarih manipülasyon deneyiminizi kesinlikle iyileştirecektir.