Bogus DateOnly/TimeOnly

Karen Payne - Sep 8 - - Dev Community

Introduction

Bogus NuGet package data generator provides methods to work with DateOnly and TimeOnly that are not documented, learn these methods using an ASP.NET Core project and class project.

Although an ASP.NET Core project is used the code presented will work with other project types. Code for creating mocked data is in a class project which other projects can use by adding a project reference to the class project. Also, no databases are used but once familiar with Bogus and EF Core or Dapper its easy to populate databases with Bogus.

Discovery

For those with little experience searching documentation will fail to produce findings for DateOnly and/or TimeOnly then search the web. A better approach is to drill down in a RuleFor as shown below to discover what is available.

Shows drilling down as described above

Usage

Class project code

Frontend project code

Backend

First create a class/model, in this case the class name is Customer with a DateOnly and TimeOnly properties which for this article is placed in a class project named BogusLibrary1.



#nullable disable

namespace BogusLibrary1.Models;
public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateOnly Birthdate { get; set; }
    public TimeOnly Time { get; set; }
}


Enter fullscreen mode Exit fullscreen mode

🔸 Add a reference/dependency for Bogus.

Next we need an interface in the class project which is optional but good practice.



using BogusLibrary1.Models;

namespace BogusLibrary1.Interfaces;

/// <summary>
/// Represents an interface for generating mocked data.
/// </summary>
public interface IMockedData
{
    /// <summary>
    /// Generates a list of customers with random time values.
    /// </summary>
    /// <param name="count">The number of customers to generate.</param>
    /// <returns>A list of customers with random time values.</returns>
    List<Customer> GetCustomersTimeOnlyRandom(int count);

    /// <summary>
    /// Generates a list of customers with recent date values and time values set to midnight.
    /// </summary>
    /// <param name="count">The number of customers to generate.</param>
    /// <returns>A list of customers with recent date values and time values set to midnight.</returns>
    List<Customer> GetCustomersDateOnlyTimeOnlyRecent(int count);

    /// <summary>
    /// Generates a list of customers with time values set to a future time.
    /// </summary>
    /// <param name="count">The number of customers to generate.</param>
    /// <returns>A list of customers with time values set to a future time.</returns>
    List<Customer> GetCustomersTimeOnlySoon(int count);

    /// <summary>
    /// Generates a list of customers with time values set to a future time within the specified date range.
    /// </summary>
    /// <param name="count">The number of customers to generate.</param>
    /// <param name="minDate">The minimum date for the time values.</param>
    /// <param name="maxDate">The maximum date for the time values.</param>
    /// <returns>A list of customers with time values set to a future time within the specified date range.</returns>
    List<Customer> GetCustomersTimeOnlySoon(int count, DateOnly minDate, DateOnly maxDate);

    /// <summary>
    /// Generates a list of customers with recent time values.
    /// </summary>
    /// <param name="count">The number of customers to generate.</param>
    /// <returns>A list of customers with recent time values.</returns>
    List<Customer> GetCustomersBetweenTimeOnlyAndDateOnly(int count);
}


Enter fullscreen mode Exit fullscreen mode

Create the class to generate lists of mocked Customers. In the code below, each method offers examples for working with DateOnly and TimeOnly using methods listed above.



using Bogus;
using BogusLibrary1.Interfaces;
using BogusLibrary1.Models;

namespace BogusLibrary1.Classes;

/// <summary>
/// Provides several methods for generating mocked data with emphasis on DateOnly, BetweenDateOnly and TimeOnly.
/// </summary>
/// <remarks>
/// See Program.cs for DI setup in BogusDateOnlyTimeOnlyApp.
/// </remarks>
public class MockedData : IMockedData
{
    /// <summary>
    /// Generate a list of customers with random time values and dates between two dates.
    /// </summary>
    /// <param name="count">How many customers to generate</param>
    /// <returns>Customers</returns>
    public List<Customer> GetCustomersTimeOnlyRandom(int count)
    {
        var identifier = 1;
        Randomizer.Seed = new Random(338);

        var faker = new Faker<Customer>()
            .CustomInstantiator(f => new Customer { Id = identifier++ })
            .RuleFor(u => u.FirstName, f => f.Name.FirstName())
            .RuleFor(c => c.LastName, f => f.Name.LastName())
            .RuleFor(c => c.Time, f =>
                f.PickRandom(new TimeOnly(9, 0),
                    new TimeOnly(12, 0),
                    new TimeOnly(15, 0)))
            .RuleFor(c => c.Birthdate, f =>
                f.Date.BetweenDateOnly(
                    new DateOnly(1950, 1, 1),
                    new DateOnly(2010, 1, 1)));

        return faker.Generate(count);

    }

    /// <summary>
    /// Generate a list of customers using RecentDateOnly and RecentTimeOnly.
    /// </summary>
    /// <param name="count">How many customers to generate</param>
    /// <returns>Customers</returns>
    public List<Customer> GetCustomersDateOnlyTimeOnlyRecent(int count)
    {

        var identifier = 1;
        Randomizer.Seed = new Random(338);

        var faker = new Faker<Customer>()
            .CustomInstantiator(f => new Customer { Id = identifier++ })
            .RuleFor(c => c.FirstName, f => f.Name.FirstName())
            .RuleFor(c => c.LastName, f => f.Name.LastName())
            .RuleFor(c => c.Time, f => f.Date.RecentTimeOnly())
            .RuleFor(c => c.Birthdate, f => f.Date.RecentDateOnly());

        return faker.Generate(count);

    }

    /// <summary>
    /// Generate a list of Customers using SoonDateOnly and SoonTimeOnly.
    /// </summary>
    /// <param name="count">How many customers to generate</param>
    /// <returns>Customers</returns>
    public List<Customer> GetCustomersTimeOnlySoon(int count)
    {
        var identifier = 1;
        Randomizer.Seed = new Random(338);

        var faker = new Faker<Customer>()
            .CustomInstantiator(f => new Customer { Id = identifier++ })
            .RuleFor(c => c.FirstName, f => f.Name.FirstName())
            .RuleFor(c => c.LastName, f => f.Name.LastName())
            .RuleFor(c => c.Time, f => f.Date.SoonTimeOnly())
            .RuleFor(c => c.Birthdate, f => f.Date.SoonDateOnly());

        return faker.Generate(count);

    }

    /// <summary>
    /// Generate a list of Customers using SoonDateOnly and BetweenDateOnly.
    /// </summary>
    /// <param name="count">How many customers to generate</param>
    /// <param name="minDate"></param>
    /// <param name="maxDate"></param>
    /// <returns>Customers</returns>
    public List<Customer> GetCustomersTimeOnlySoon(int count, DateOnly minDate, DateOnly maxDate)
    {
        var identifier = 1;
        Randomizer.Seed = new Random(338);

        var faker = new Faker<Customer>()
            .CustomInstantiator(f => new Customer { Id = identifier++ })
            .RuleFor(c => c.FirstName, f => f.Name.FirstName())
            .RuleFor(c => c.LastName, f => f.Name.LastName())
            .RuleFor(c => c.Time, f => f.Date.SoonTimeOnly())
            .RuleFor(c => c.Birthdate, f =>
                f.Date.BetweenDateOnly(minDate, maxDate));

        return faker.Generate(count);

    }



    /// <summary>
    /// Generate a list of Customers using RecentTimeOnly and BetweenDateOnly.
    /// </summary>
    /// <param name="count">How many customers to generate</param>
    /// <returns>Customers</returns>
    public List<Customer> GetCustomersBetweenTimeOnlyAndDateOnly(int count)
    {
        var identifier = 1;
        Randomizer.Seed = new Random(338);

        var faker = new Faker<Customer>()
            .CustomInstantiator(f => new Customer { Id = identifier++ })
            .RuleFor(u => u.FirstName, f => f.Name.FirstName())
            .RuleFor(c => c.LastName, f => f.Name.LastName())
            .RuleFor(c => c.Time, f => f.Date.BetweenTimeOnly(
                new TimeOnly(8,0,0),
                new TimeOnly(14,0,0)))
            .RuleFor(c => c.Birthdate, f =>
                f.Date.BetweenDateOnly(
                    new DateOnly(1950, 1, 1),
                    new DateOnly(2010, 1, 1)));

        return faker.Generate(count);

    }
}


Enter fullscreen mode Exit fullscreen mode

Frontend

Since the majority of applications are web based, the frontend will be a simple ASP.NET Core project.

  • Create a new ASP.NET Core project, in this case named BogusDateOnlyTimeOnlyApp.
  • Add a project reference to the class project above by single clicking the class project and drag to the new ASP.NET Core project and drop on the root of the project.
  • Setup the service in Program.cs of the ASP.NET Core project and add necessary using statements as shown below.

frontend program.cs

To keep this simple all code is done in index page. For three samples there is a property and in OnGet each property is populated.



using BogusLibrary1.Interfaces;
using BogusLibrary1.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;


namespace BogusDateOnlyTimeOnlyApp.Pages;
public class IndexModel(IMockedData mockedData) : PageModel
{
    [BindProperty]
    public required List<Customer> CustomersRecent { get; set; }
    [BindProperty]
    public required List<Customer> CustomersSoon { get; set; }
    [BindProperty]
    public required List<Customer> CustomersBetween { get; set; }

    public void OnGet()
    {
        CustomersRecent = mockedData.GetCustomersDateOnlyTimeOnlyRecent(5);
        CustomersSoon = mockedData.GetCustomersTimeOnlySoon(5);
        CustomersBetween = mockedData.GetCustomersBetweenTimeOnlyAndDateOnly(5);
    }
}


Enter fullscreen mode Exit fullscreen mode

For HTML, see the provided code as there is no reason to display that code here.

Shown in Chrome web browser.

Results displayed in a browser

Determine when mocked data is needed

There are several idea, the first with EF Core, in the DbContext, OnModelCreating setup a flag perhaps read from appsettings.json to determine to create mocked data as shown below.



protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Customer>(entity =>
    {

    ...

    /*
     * Determine if we should create new data or not. Uses value from appsettings.json
     */
    if (!EntitySettings.Instance.CreateNew) return;
    modelBuilder.Entity<Customer>().HasData(new List<Customer>(MockedData.GetCustomersTimeOnlyRandom(100)));
}


Enter fullscreen mode Exit fullscreen mode

Similar to the EF Core example, have an if statement at program start to either use mocked data or live data.

When working with a database using one of the methods above with or without EF Core consider in development environments to remove existing data and populating with mocked data.

When populating as mentioned above consider first using the following for working with a connection/command objects or Dapper to start the primary key at 1.



DBCC CHECKIDENT ([Products], RESEED, 0)


Enter fullscreen mode Exit fullscreen mode

With EF Core use the following.



context.Database.EnsureDeleted();
context.Database.EnsureCreated();

Enter fullscreen mode Exit fullscreen mode




Summary

Using the information provided a developer can create mocked data for DateOnly and TimeOnly for a variety of task using Bogus NuGet package.

See also

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .