Skip to content

A full-stack sample project showing how to store and display timestamps correctly across timezones. It demonstrates saving UTC timestamps on a .NET 8 Web API backend and displaying local times dynamically on an Angular 20 frontend.

Notifications You must be signed in to change notification settings

rbasehewa/angular-dotnet-timeoffset

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Angular + .NET TimeOffset Demo

A full-stack sample project demonstrating best practices for handling timestamps across timezones in modern web applications.

🎯 Overview

This project solves a common problem in distributed applications: how to correctly store and display timestamps when users are in different timezones.

The solution demonstrates:

  • Storing all timestamps as UTC on the backend (.NET 8 Web API)
  • Dynamically displaying timestamps in the user's local timezone on the frontend (Angular 20)
  • Proper timezone conversion without data loss
  • RESTful API design with proper date handling

πŸš€ Key Features

  • UTC Storage: All timestamps stored as UTC in the database/API
  • Automatic Timezone Conversion: Frontend dynamically converts UTC to user's local time
  • Timezone-Aware Display: Shows times in user-friendly formats with timezone information
  • RESTful API: Clean .NET 8 Web API with proper ISO 8601 date serialization
  • Modern Frontend: Built with Angular 20 using standalone components
  • Type Safety: Full TypeScript implementation with proper date type handling

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Angular 20 Frontend         β”‚
β”‚                                     β”‚
β”‚  β€’ Receives UTC timestamps          β”‚
β”‚  β€’ Converts to local timezone       β”‚
β”‚  β€’ Displays in user-friendly format β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ HTTP/REST
               β”‚ JSON (ISO 8601)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚        .NET 8 Web API               β”‚
β”‚                                     β”‚
β”‚  β€’ Stores UTC timestamps            β”‚
β”‚  β€’ Returns ISO 8601 formatted dates β”‚
β”‚  β€’ Timezone-agnostic data layer     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ› οΈ Tech Stack

Backend

  • .NET 8 - Latest LTS version
  • ASP.NET Core Web API - RESTful API framework
  • C# 12 - Modern language features
  • Entity Framework Core (if applicable)

Frontend

  • Angular 20 - Latest Angular framework
  • TypeScript 5.0 - Type-safe JavaScript
  • RxJS - Reactive programming
  • Angular Standalone Components - Modern Angular architecture

πŸ“‹ Prerequisites

πŸš€ Getting Started

1. Clone the Repository

git clone https://github.com/rbasehewa/angular-dotnet-timeoffset.git
cd angular-dotnet-timeoffset

2. Run the Backend (.NET API)

cd TimezoneApi
dotnet restore
dotnet run

The API will start at https://localhost:5001 (or http://localhost:5000)

3. Run the Frontend (Angular)

cd timezone-ui
npm install
ng serve

The application will open at http://localhost:4200

πŸ’‘ How It Works

Backend (.NET 8)

The API always stores and returns timestamps in UTC:

public class TimeEntry
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; } // Always stored as UTC
    public string Description { get; set; }
}

[HttpPost]
public IActionResult CreateEntry([FromBody] TimeEntry entry)
{
    entry.CreatedAt = DateTime.UtcNow; // Force UTC
    // Save to database...
    return Ok(entry);
}

Frontend (Angular 20)

The Angular app receives UTC and converts to local time:

export class TimeDisplayComponent {
  entries: TimeEntry[] = [];

  ngOnInit() {
    this.http.get<TimeEntry[]>('/api/entries')
      .subscribe(entries => {
        this.entries = entries.map(entry => ({
          ...entry,
          // JavaScript Date automatically converts UTC to local
          createdAt: new Date(entry.createdAt)
        }));
      });
  }
}

Template displays local time:

<div *ngFor="let entry of entries">
  <p>Created: {{ entry.createdAt | date:'medium' }}</p>
  <!-- Shows: "Jan 26, 2026, 2:30:45 PM" in user's timezone -->
</div>

πŸŽ“ Key Concepts Demonstrated

1. Always Store UTC

  • Database and API never store local times
  • Eliminates ambiguity during DST transitions
  • Enables accurate time calculations

2. ISO 8601 Format

  • API returns dates like "2026-01-26T14:30:45.123Z"
  • The Z indicates UTC (Zulu time)
  • Universal standard for date interchange

3. Client-Side Conversion

  • Browser automatically handles timezone conversion
  • Respects user's system timezone settings
  • No server-side timezone logic needed

4. Date Pipe in Angular

  • Angular's built-in date pipe handles formatting
  • Automatically uses browser's locale
  • Customizable formats (short, medium, long, full)

πŸ§ͺ Testing Different Timezones

You can test timezone handling by:

  1. Changing System Timezone:

    • Windows: Settings β†’ Time & Language β†’ Date & Time
    • macOS: System Preferences β†’ Date & Time
    • Linux: timedatectl set-timezone [timezone]
  2. Browser DevTools:

    • Open Chrome DevTools
    • Press Ctrl+Shift+P (Cmd+Shift+P on Mac)
    • Type "timezone" and select "Show Sensors"
    • Choose a different timezone
  3. Expected Behavior:

    • Same UTC timestamp from API
    • Different local display time
    • Correct relative time calculations

πŸ“ Project Structure

angular-dotnet-timeoffset/
β”œβ”€β”€ TimezoneApi/                 # .NET 8 Web API
β”‚   β”œβ”€β”€ Controllers/
β”‚   β”‚   └── TimeEntriesController.cs
β”‚   β”œβ”€β”€ Models/
β”‚   β”‚   └── TimeEntry.cs
β”‚   β”œβ”€β”€ Program.cs
β”‚   └── appsettings.json
β”‚
└── timezone-ui/                 # Angular 20 Frontend
    β”œβ”€β”€ src/
    β”‚   β”œβ”€β”€ app/
    β”‚   β”‚   β”œβ”€β”€ components/
    β”‚   β”‚   β”œβ”€β”€ services/
    β”‚   β”‚   └── models/
    β”‚   └── environments/
    └── angular.json

πŸ”§ Configuration

API Configuration (appsettings.json)

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "AllowedHosts": "*",
  "Cors": {
    "AllowedOrigins": ["http://localhost:4200"]
  }
}

Angular Environment

export const environment = {
  production: false,
  apiUrl: 'https://localhost:5001/api'
};

πŸ› Common Issues & Solutions

Issue: Dates display as UTC strings

Solution: Ensure you're converting string dates to JavaScript Date objects:

createdAt: new Date(entry.createdAt)

Issue: Times are off by several hours

Solution: Check that API is returning dates with Z suffix (UTC indicator)

Issue: CORS errors

Solution: Ensure CORS is configured in the .NET API:

builder.Services.AddCors(options => {
    options.AddDefaultPolicy(builder => {
        builder.WithOrigins("http://localhost:4200")
               .AllowAnyMethod()
               .AllowAnyHeader();
    });
});

πŸ“š Learn More

Related Articles

Best Practices

  • βœ… Always store timestamps as UTC in the database
  • βœ… Use ISO 8601 format for date serialization
  • βœ… Convert to local time only on display
  • βœ… Use timezone-aware date libraries when needed
  • βœ… Consider user's timezone preference for multi-tenant apps

🀝 Contributing

Contributions are welcome! This is a reference implementation, so issues and pull requests that improve clarity or demonstrate additional patterns are appreciated.

πŸ“ License

This project is open source and available under the MIT License.

πŸ‘€ Author

Ryan Maddumahewa

⭐ Show Your Support

If this project helped you understand timezone handling in full-stack applications, please give it a star! ⭐


Built with ❀️ using .NET 8 and Angular 20

About

A full-stack sample project showing how to store and display timestamps correctly across timezones. It demonstrates saving UTC timestamps on a .NET 8 Web API backend and displaying local times dynamically on an Angular 20 frontend.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published