Skip to content

Commit

Permalink
accept date
Browse files Browse the repository at this point in the history
  • Loading branch information
badra001 committed Jan 30, 2026
1 parent ed54be4 commit a48c788
Showing 1 changed file with 33 additions and 25 deletions.
58 changes: 33 additions & 25 deletions local-app/python-tools/billing/aws_monthly_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,44 @@
import argparse
import sys
from botocore.exceptions import ClientError, ProfileNotFound
from dateutil.parser import parse

__version__ = "1.0.1"
__version__ = "1.0.2"

def get_monthly_range(target_date=None):
"""Calculates start of current month and start of next month (exclusive)."""
if target_date is None:
def get_monthly_range(date_str=None):
"""
Parses a date string and returns the first day of that month
and the first day of the following month.
"""
if date_str:
try:
target_date = parse(date_str).date()
except ValueError:
print(f"❌ Error: Could not parse date '{date_str}'. Use YYYY-MM or YYYY-MM-DD.")
sys.exit(1)
else:
target_date = datetime.date.today()

# Start of the month for the provided date
start = target_date.replace(day=1)

# Start of the next month
if start.month == 12:
end = start.replace(year=start.year + 1, month=1)
else:
end = start.replace(month=start.month + 1)

return start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')

def fetch_aws_costs(profile, region):
def fetch_aws_costs(profile, region, date_arg):
try:
# Initialize session with user parameters
session = boto3.Session(profile_name=profile, region_name=region)

# Cost Explorer API is globally managed via us-east-1 endpoint
client = session.client('ce', region_name='us-east-1')

start_date, end_date = get_monthly_range()
start_date, end_date = get_monthly_range(date_arg)

print(f"--- AWS Monthly Cost Summary v{__version__} ---")
print(f"Profile: {profile or 'default'}")
print(f"Region: {region}")
print(f"Period: {start_date} to {end_date}\n")

response = client.get_cost_and_usage(
Expand All @@ -48,21 +58,20 @@ def fetch_aws_costs(profile, region):

for group in response['ResultsByTime'][0]['Groups']:
service_name = group['Keys'][0]
metrics = group['Metrics']
m = group['Metrics']

usage_qty = float(metrics['UsageQuantity']['Amount'])
usage_unit = metrics['UsageQuantity']['Unit']
blended = float(metrics['BlendedCost']['Amount'])
unblended = float(metrics['UnblendedCost']['Amount'])
amortized = float(metrics['AmortizedCost']['Amount'])
qty = float(m['UsageQuantity']['Amount'])
unit = m['UsageQuantity']['Unit']
blended = float(m['BlendedCost']['Amount'])
unblended = float(m['UnblendedCost']['Amount'])
amortized = float(m['AmortizedCost']['Amount'])

rows.append([service_name, f"{usage_qty:.2f}", usage_unit, f"{blended:.2f}", f"{unblended:.2f}", f"{amortized:.2f}"])
rows.append([service_name, f"{qty:.2f}", unit, f"{blended:.2f}", f"{unblended:.2f}", f"{amortized:.2f}"])

grand_totals['blended'] += blended
grand_totals['unblended'] += unblended
grand_totals['amortized'] += amortized

# Sort by Total Cost descending
rows.sort(key=lambda x: float(x[5]), reverse=True)

filename = f"aws_cost_{start_date[:7]}.csv"
Expand All @@ -78,17 +87,16 @@ def fetch_aws_costs(profile, region):
print(f"✅ Success! Report saved as: {filename}")

except ProfileNotFound:
print(f"❌ Error: The profile '{profile}' was not found in your AWS config.")
print(f"❌ Error: Profile '{profile}' not found.")
except ClientError as e:
print(f"❌ AWS Error: {e}")
except Exception as e:
print(f"❌ Unexpected Error: {e}")

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate AWS Monthly Cost CSV")
parser.add_argument('--profile', type=str, help="AWS CLI profile to use", default=None)
parser.add_argument('--region', type=str, help="AWS region (default: us-east-1)", default='us-east-1')
parser = argparse.ArgumentParser(description="AWS Monthly Cost to CSV")
parser.add_argument('date', nargs='?', help="Date in YYYY-MM or YYYY-MM-DD format (default: today)")
parser.add_argument('--profile', type=str, help="AWS CLI profile")
parser.add_argument('--region', type=str, default='us-east-1', help="AWS region")
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')

args = parser.parse_args()
fetch_aws_costs(args.profile, args.region)
fetch_aws_costs(args.profile, args.region, args.date)

0 comments on commit a48c788

Please sign in to comment.