import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;

class Main {
    public static void main(String[] args) {
        // Replace ZoneId.systemDefault() with the applicable ZoneId e.g.
        // ZoneId.of("America/New_York")
        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault());
        System.out.println(zdt);

        zdt = zdt.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println(zdt);

        zdt = zdt.withHour(LocalTime.MIN.getHour());
        System.out.println(zdt);

        zdt = zdt.withMinute(LocalTime.MIN.getMinute());
        System.out.println(zdt);

        zdt = zdt.withSecond(LocalTime.MIN.getSecond());
        System.out.println(zdt);

        zdt = zdt.with(ChronoField.MILLI_OF_SECOND, LocalTime.MIN.getLong(ChronoField.MILLI_OF_SECOND));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        System.out.println(zdt.format(formatter));

        // In a single statement
        String output = ZonedDateTime.now(ZoneId.systemDefault())
                .with(TemporalAdjusters.firstDayOfMonth())
                .withHour(LocalTime.MIN.getHour())
                .withMinute(LocalTime.MIN.getMinute())
                .withSecond(LocalTime.MIN.getSecond())
                .with(ChronoField.MILLI_OF_SECOND, LocalTime.MIN.getLong(ChronoField.MILLI_OF_SECOND))
                .format(formatter);
        System.out.println(output);

        // There is a better way if all you want is day-1 with minimum time
        zdt = LocalDate.now(ZoneId.systemDefault())
                .with(TemporalAdjusters.firstDayOfMonth())
                .atStartOfDay()
                .atZone(ZoneId.systemDefault());
        System.out.println(zdt.format(formatter));
    }
}