Skip to main content
Obsidian includes the Moment.js library for parsing, validating, manipulating, and formatting dates and times.

Overview

The moment object in Obsidian is a direct reference to the Moment.js library. You can use it to:
  • Parse dates in various formats
  • Format dates for display
  • Manipulate dates (add/subtract time)
  • Compare dates
  • Work with time zones and locales

Importing moment

import { moment } from 'obsidian';

Basic Usage

Creating Moments

import { moment } from 'obsidian';

// Current date and time
const now = moment();

// Parse a date string
const date1 = moment('2024-03-15');
const date2 = moment('March 15, 2024', 'MMMM DD, YYYY');

// From a JavaScript Date
const jsDate = new Date();
const date3 = moment(jsDate);

// From a timestamp
const date4 = moment(1710504000000);

// From an array [year, month, day, hour, minute, second, millisecond]
const date5 = moment([2024, 2, 15]); // March 15, 2024 (months are 0-indexed)

Formatting Dates

const date = moment('2024-03-15');

// Common formats
date.format('YYYY-MM-DD');           // "2024-03-15"
date.format('MMM DD, YYYY');         // "Mar 15, 2024"
date.format('MMMM Do YYYY');         // "March 15th 2024"
date.format('dddd, MMMM Do YYYY');   // "Friday, March 15th 2024"
date.format('h:mm A');               // "12:00 AM"
date.format('YYYY-MM-DD HH:mm:ss');  // "2024-03-15 00:00:00"

// Relative time
date.fromNow();                      // "2 days ago" (relative to now)
date.from(moment('2024-03-20'));     // "5 days ago" (relative to another date)
date.toNow();                        // "in 2 days" (from perspective of date)
date.calendar();                     // "Last Friday at 12:00 AM"

Common Use Cases in Obsidian

Daily Notes

class DailyNotesPlugin extends Plugin {
  async createDailyNote() {
    const today = moment().format('YYYY-MM-DD');
    const fileName = `${today}.md`;
    
    const file = this.app.vault.getAbstractFileByPath(`Daily/${fileName}`);
    
    if (!file) {
      await this.app.vault.create(`Daily/${fileName}`, 
        `# ${moment().format('MMMM Do, YYYY')}\n\n`
      );
    }
  }
  
  async openTodayNote() {
    const today = moment().format('YYYY-MM-DD');
    const file = this.app.vault.getAbstractFileByPath(`Daily/${today}.md`);
    
    if (file instanceof TFile) {
      await this.app.workspace.getLeaf().openFile(file);
    }
  }
}

Formatting File Dates

class MyPlugin extends Plugin {
  formatFileDate(file: TFile): string {
    const mtime = moment(file.stat.mtime);
    
    // Show relative time if recent
    if (mtime.isAfter(moment().subtract(7, 'days'))) {
      return mtime.fromNow();
    }
    
    // Otherwise show formatted date
    return mtime.format('MMM DD, YYYY');
  }
  
  displayFileInfo(file: TFile) {
    const created = moment(file.stat.ctime);
    const modified = moment(file.stat.mtime);
    
    console.log(`Created: ${created.format('YYYY-MM-DD HH:mm')}`);
    console.log(`Modified: ${modified.fromNow()}`);
    console.log(`Age: ${created.toNow(true)}`);
  }
}

Date Manipulation

import { moment } from 'obsidian';

// Add time
const tomorrow = moment().add(1, 'day');
const nextWeek = moment().add(1, 'week');
const nextMonth = moment().add(1, 'month');
const in90Minutes = moment().add(90, 'minutes');

// Subtract time
const yesterday = moment().subtract(1, 'day');
const lastWeek = moment().subtract(1, 'week');
const lastYear = moment().subtract(1, 'year');

// Start/end of period
const startOfDay = moment().startOf('day');
const endOfMonth = moment().endOf('month');
const startOfWeek = moment().startOf('week');

// Chaining
const date = moment()
  .add(1, 'month')
  .subtract(3, 'days')
  .startOf('day');

Date Comparisons

const date1 = moment('2024-03-15');
const date2 = moment('2024-03-20');

// Comparison methods
date1.isBefore(date2);           // true
date1.isAfter(date2);            // false
date1.isSame(date2);             // false
date1.isSameOrBefore(date2);     // true
date1.isSameOrAfter(date2);      // false
date1.isBetween(date2, date3);   // check if between two dates

// Comparison with granularity
date1.isSame(date2, 'month');    // true (same month)
date1.isSame(date2, 'day');      // false (different day)

// Difference between dates
const daysDiff = date2.diff(date1, 'days');        // 5
const hoursDiff = date2.diff(date1, 'hours');      // 120
const yearsDiff = moment().diff('1990-01-01', 'years'); // age calculation

Parsing Custom Formats

class MyPlugin extends Plugin {
  parseDateFromFilename(filename: string): moment.Moment | null {
    // Try multiple date formats
    const formats = [
      'YYYY-MM-DD',
      'YYYYMMDD',
      'MM-DD-YYYY',
      'DD.MM.YYYY'
    ];
    
    for (const format of formats) {
      const parsed = moment(filename, format, true); // strict parsing
      if (parsed.isValid()) {
        return parsed;
      }
    }
    
    return null;
  }
  
  extractDatesFromContent(content: string): moment.Moment[] {
    const dates: moment.Moment[] = [];
    const dateRegex = /\d{4}-\d{2}-\d{2}/g;
    const matches = content.match(dateRegex);
    
    if (matches) {
      for (const match of matches) {
        const date = moment(match, 'YYYY-MM-DD');
        if (date.isValid()) {
          dates.push(date);
        }
      }
    }
    
    return dates;
  }
}

Task Management

class TaskPlugin extends Plugin {
  isTaskOverdue(task: { dueDate: string }): boolean {
    const due = moment(task.dueDate);
    return due.isValid() && due.isBefore(moment(), 'day');
  }
  
  getTaskStatus(task: { dueDate: string }): string {
    const due = moment(task.dueDate);
    
    if (!due.isValid()) {
      return 'No due date';
    }
    
    const now = moment();
    
    if (due.isBefore(now, 'day')) {
      return `Overdue by ${now.diff(due, 'days')} days`;
    }
    
    if (due.isSame(now, 'day')) {
      return 'Due today';
    }
    
    if (due.isSame(now.add(1, 'day'), 'day')) {
      return 'Due tomorrow';
    }
    
    return `Due in ${due.diff(now, 'days')} days`;
  }
  
  sortTasksByDueDate(tasks: Array<{ dueDate: string }>) {
    return tasks.sort((a, b) => {
      const dateA = moment(a.dueDate);
      const dateB = moment(b.dueDate);
      
      if (!dateA.isValid()) return 1;
      if (!dateB.isValid()) return -1;
      
      return dateA.diff(dateB);
    });
  }
}

Common Format Tokens

TokenExampleDescription
YYYY20244-digit year
YY242-digit year
MMMMMarchFull month name
MMMMarShort month name
MM03Month (01-12)
M3Month (1-12)
DD15Day with leading zero
D15Day without leading zero
ddddFridayFull day name
dddFriShort day name
HH14Hour (00-23)
hh02Hour (01-12)
mm05Minutes
ss30Seconds
APMAM/PM
Do15thDay with ordinal

Validation

const date = moment('2024-03-15');

// Check if valid
if (date.isValid()) {
  console.log('Valid date');
} else {
  console.log('Invalid date');
}

// Strict parsing
const strictDate = moment('03/15/2024', 'MM/DD/YYYY', true);
if (strictDate.isValid()) {
  console.log('Matches format exactly');
}

// Check for specific date properties
date.isLeapYear();           // Check if leap year
date.isBefore(moment());     // Check if in the past
date.isAfter(moment());      // Check if in the future

MomentFormatComponent

Obsidian also provides a MomentFormatComponent for building date format pickers in settings:
class MySettingTab extends PluginSettingTab {
  display() {
    const { containerEl } = this;
    containerEl.empty();
    
    new Setting(containerEl)
      .setName('Date format')
      .setDesc('Format for displaying dates')
      .addMomentFormat((format) => {
        format
          .setDefaultFormat('YYYY-MM-DD')
          .setValue(this.plugin.settings.dateFormat)
          .onChange(async (value) => {
            this.plugin.settings.dateFormat = value;
            await this.plugin.saveSettings();
          });
      });
  }
}

Best Practices

Use ISO 8601 Format for Storage

Always store dates in ISO 8601 format (YYYY-MM-DD) for consistency:
// Good
const dateString = moment().format('YYYY-MM-DD');
await this.app.vault.create('note.md', `date: ${dateString}`);

// Bad - ambiguous format
const dateString = moment().format('MM/DD/YY');

Validate Dates

Always check if a moment is valid before using it:
function processDate(dateString: string) {
  const date = moment(dateString);
  
  if (!date.isValid()) {
    new Notice('Invalid date format');
    return;
  }
  
  // Use the date
  console.log(date.format('YYYY-MM-DD'));
}

Use Relative Times for Recent Events

function formatDate(timestamp: number): string {
  const date = moment(timestamp);
  const now = moment();
  
  // Show relative time if within last week
  if (date.isAfter(now.subtract(7, 'days'))) {
    return date.fromNow();
  }
  
  // Otherwise show formatted date
  return date.format('MMM DD, YYYY');
}

Further Reading

While Moment.js is included in Obsidian for convenience, note that Moment.js is in maintenance mode. For new projects outside of Obsidian, consider alternatives like Day.js or date-fns. However, since Obsidian includes Moment.js, it’s perfectly fine to use it in your plugins.

Build docs developers (and LLMs) love