npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

tempo-sync

v1.0.0

Published

Lightweight JavaScript library for automatic relative time updates with intelligent shared timer

Readme

tempo-sync

npm version License: MIT Tests

tempo-sync is a lightweight (3KB) JavaScript library that automatically updates all relative time elements on your page ("2 hours ago", "just now", etc.) using a single, intelligent shared timer.

✨ Key Features

  • 🎯 One Timer for Everything - Instead of each timestamp creating its own timer, all elements share one smart timer
  • 🧠 Smart Update Intervals - Updates "seconds ago" every second, "minutes ago" every minute, "hours ago" every hour, etc.
  • 🪶 Zero Dependencies - Pure vanilla JS using native browser APIs
  • 🔧 Framework Agnostic - Works with any HTML, React, Vue, Angular, etc.
  • 🧹 Auto-cleanup - Automatically stops tracking removed elements
  • ⚡ Performance Optimized - Minimal CPU/battery usage

🚀 Quick Start

Installation

npm install tempo-sync

Or use via CDN:

<script src="https://unpkg.com/tempo-sync@latest/dist/tempo-sync.min.js"></script>

Basic Usage

<!-- Add data-tempo attribute to any element -->
<span data-tempo="2024-01-15T10:30:00Z">2 hours ago</span>
<div data-tempo="2024-01-15T08:00:00Z">4 hours ago</div>
<time data-tempo="2024-01-14T12:00:00Z">Yesterday</time>

<script>
// Initialize once
tempoSync.observe();
</script>

That's it! All timestamps will now update automatically at intelligent intervals.

📖 API Reference

tempoSync.observe()

Starts observing elements with data-tempo attributes and begins automatic updates.

tempoSync.observe();

tempoSync.disconnect()

Stops observing and cleans up all timers and observers.

tempoSync.disconnect();

tempoSync.addElement(element)

Manually add an element to be tracked (usually not needed as observe() handles this automatically).

const element = document.querySelector('[data-tempo]');
tempoSync.addElement(element);

tempoSync.removeElement(element)

Manually remove an element from tracking.

tempoSync.removeElement(element);

🎨 Examples

Social Media Feed

<div class="post">
  <h3>John shared a photo</h3>
  <span data-tempo="2024-01-15T14:30:00Z">2 hours ago</span>
</div>

<div class="comment">
  <p>Great photo!</p>
  <small data-tempo="2024-01-15T15:45:00Z">45 minutes ago</small>
</div>

Dashboard with Live Updates

<div class="metrics">
  <div class="metric">
    <span>Last backup:</span>
    <span data-tempo="2024-01-15T12:00:00Z">4 hours ago</span>
  </div>
  <div class="metric">
    <span>Server restart:</span>
    <span data-tempo="2024-01-15T06:30:00Z">10 hours ago</span>
  </div>
</div>

React Integration

import { useEffect } from 'react';

function App() {
  useEffect(() => {
    // Initialize tempo-sync when component mounts
    tempoSync.observe();
    
    // Cleanup when component unmounts
    return () => tempoSync.disconnect();
  }, []);

  return (
    <div>
      <span data-tempo={new Date(Date.now() - 300000).toISOString()}>
        5 minutes ago
      </span>
    </div>
  );
}

Vue Integration

<template>
  <div>
    <span :data-tempo="timestamp">{{ relativeTime }}</span>
  </div>
</template>

<script>
export default {
  data() {
    return {
      timestamp: new Date(Date.now() - 600000).toISOString(), // 10 minutes ago
      relativeTime: '10 minutes ago'
    };
  },
  mounted() {
    tempoSync.observe();
  },
  beforeUnmount() {
    tempoSync.disconnect();
  }
};
</script>

⚡ Performance Benefits

The Problem

Most relative time libraries create multiple timers (one per element) that update inefficiently:

// ❌ Traditional approach - wasteful
setInterval(() => updateElement1(), 1000); // Updates "3 days ago" every second
setInterval(() => updateElement2(), 1000); // Updates "1 year ago" every second
setInterval(() => updateElement3(), 1000); // Updates "just now" every second

The Solution

tempo-sync uses one intelligent timer that knows when each element actually needs updating:

// ✅ tempo-sync approach - efficient
// "just now" updates every second
// "5 minutes ago" updates every minute
// "3 hours ago" updates every hour
// "2 days ago" updates daily

Benchmark Results

| Elements | Traditional | tempo-sync | CPU Savings | |----------|-------------|------------|-------------| | 10 | 10 timers | 1 timer | 90% | | 100 | 100 timers | 1 timer | 99% | | 1000 | 1000 timers | 1 timer | 99.9% |

🕐 Time Formats

tempo-sync automatically formats time differences into human-readable strings:

| Time Difference | Output | Update Frequency | |----------------|--------|------------------| | < 1 minute | "just now" | Every second | | 1-59 minutes | "X minutes ago" | Every minute | | 1-23 hours | "X hours ago" | Every hour | | 1-6 days | "X days ago" | Every day | | 1-4 weeks | "X weeks ago" | Every day | | 1-11 months | "X months ago" | Every day | | 1+ years | "X years ago" | Every day |

Future Times

tempo-sync also supports future timestamps:

  • "in 5 minutes"
  • "in 2 hours"
  • "in 3 days"

🔧 Advanced Usage

Manual Control

// Start/stop as needed
tempoSync.observe();

// Later...
tempoSync.disconnect();

// Restart
tempoSync.observe();

Dynamic Content

tempo-sync automatically detects new elements added to the DOM:

// This will be automatically tracked
const newElement = document.createElement('span');
newElement.setAttribute('data-tempo', new Date().toISOString());
newElement.textContent = 'just now';
document.body.appendChild(newElement);

Custom Timestamps

// Any valid ISO 8601 timestamp works
const timestamps = [
  '2024-01-15T10:30:00Z',           // UTC
  '2024-01-15T10:30:00-05:00',      // With timezone
  '2024-01-15T10:30:00.123Z',       // With milliseconds
  new Date().toISOString()           // Current time
];

🌐 Browser Support

  • Chrome 51+
  • Firefox 55+
  • Safari 10+
  • Edge 79+
  • IE 11+ (with polyfills)

📦 Module Systems

tempo-sync supports all module systems:

ES Modules

import tempoSync from 'tempo-sync';

CommonJS

const tempoSync = require('tempo-sync');

AMD

define(['tempo-sync'], function(tempoSync) {
  // Use tempoSync
});

Global

<script src="tempo-sync.min.js"></script>
<script>
  // tempoSync is available globally
  tempoSync.observe();
</script>

🧪 Testing

Run the test suite:

npm test

Or with Jest:

npm run test:jest

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📊 Bundle Size

  • Minified: 3KB
  • Gzipped: ~1.2KB
  • Zero dependencies

Made with ❤️ by Else Lab

WebsiteGitHubContact