# One Off-Hours Schedule Across AWS, GCP and Azure VMs

> Stop VMs at 19:00 local time on AWS, Google Cloud and Azure with each native scheduler, and handle their different timezone rules, delays and billing states.

Source: https://zop.dev/learn/how-to/set-up-multi-cloud-scheduling
Published: 2026-07-01 · Updated: 2026-09-24 · Author: avinash-gaurav · Tags: zopnight, how-to, learn

---

The same 07:00 to 19:00 weekday window, expressed three ways, and the three places each native scheduler behaves differently.

Say the policy is simple: development VMs run 07:00 to 19:00 on weekdays, office time in Bengaluru, and are off otherwise. Each cloud has a native way to do this, and each takes the time, the timezone and the start in a different form. This page writes the same window three times and points out where the results diverge.

## AWS: EventBridge Scheduler

EventBridge Scheduler takes a six-field cron and a named timezone, and calls the EC2 API through a universal target. The full role and target setup is in <a href="https://zop.dev/learn/how-to/automate-cloud-resource-scheduling">automating EC2 stop and start with EventBridge Scheduler</a>; the schedule expressions for this window are:

```bash
--schedule-expression "cron(0 19 ? * MON-FRI *)" --schedule-expression-timezone "Asia/Kolkata"   # stop
--schedule-expression "cron(0 7 ? * MON-FRI *)"  --schedule-expression-timezone "Asia/Kolkata"   # start
```

Stopped instances stop billing for compute; EBS volumes and Elastic IPs keep billing.

## Google Cloud: instance schedules

Compute Engine has a built-in instance schedule, which is a resource policy with both a start and a stop cron in standard five-field form:

```bash
gcloud compute resource-policies create instance-schedule dev-office-hours \
  --region=asia-south1 \
  --vm-start-schedule="0 7 * * 1-5" \
  --vm-stop-schedule="0 19 * * 1-5" \
  --timezone="Asia/Kolkata" \
  --description="Dev VMs, weekday office hours"

gcloud compute instances add-resource-policies dev-vm-01 \
  --resource-policies=dev-office-hours --zone=asia-south1-a
```

Before it works, grant the Compute Engine Service Agent the Compute Instance Admin (v1) role (`roles/compute.instanceAdmin.v1`) on the project; the person creating the schedule needs it too. Google documents several limits worth planning around:

- The schedule and its VMs must be in the same region, and each VM can follow only one schedule.
- An operation can begin up to 15 minutes after the scheduled time, and start and stop should be at least 15 minutes apart.
- Instance schedules cannot stop a VM that has Local SSD disks.

A stopped VM keeps its disks, IP addresses and metadata, and Google keeps charging for resources that stay attached to it.

## Azure: auto-shutdown

Azure's built-in option is auto-shutdown, set in the portal under the VM's **Operations** section or from the CLI:

```bash
az vm auto-shutdown -g dev-rg -n dev-vm-01 --time 1330 --email "platform@example.com"
```

Two differences stand out. `--time` is the UTC time of day in `hhmm` format, so 19:00 in India is `1330` and there is no named-timezone option in the command. And the command sets a shutdown only; nothing in `az vm auto-shutdown` starts the VM again, so the morning start needs a separate mechanism. Remove the setting with `--off`.

Check the resulting power state. Azure bills a VM in the **Stopped** (allocated) state, which is what a shutdown from inside the guest OS produces. Only **Stopped (deallocated)** stops compute billing, and disks and networking continue to charge either way.

```bash
az vm get-instance-view -g dev-rg -n dev-vm-01 \
  --query "instanceView.statuses[?starts_with(code,'PowerState')].displayStatus" -o tsv
```

## Verify all three the same evening

```bash
aws ec2 describe-instances --filters "Name=tag:env,Values=dev" \
  --query "Reservations[].Instances[].[InstanceId,State.Name]" --output text
gcloud compute instances list --filter="name~^dev-" --format="table(name,status)"
```

Expect `stopped` on AWS and `TERMINATED` on Google Cloud (the state Compute Engine uses for a stopped VM). On Azure, the instance-view query above should report a deallocated power state, which the portal shows as Stopped (deallocated).

## Keeping three definitions in step

The weak point is drift: someone moves the AWS stop to 20:00 and the other two stay at 19:00, or the Azure UTC offset is wrong after a team moves region. ZopNight keeps one schedule definition, with an IANA timezone and cron start and stop expressions, and attaches it to EC2, Compute Engine and Azure VMs alike; on Azure the execution deallocates rather than just stopping. Resource groups let a mixed set of VMs share the schedule, and a weekly 24-hour grid shows the window before you save. Per-resource details live on the <a href="https://zop.dev/integrations/gcp/compute/schedule">Compute Engine</a> and <a href="https://zop.dev/integrations/azure/vm/schedule">Azure VM</a> scheduling pages.
