phone number standards
phone number standards
Malaysia Phone Number Format: Complete Validation Guide & E.164 Conversion (2025)
Master Malaysian phone number validation with code examples in JavaScript, Python, PHP & Java. Includes MCMC regulations, E.164 conversion, WhatsApp formatting, IRBM e-invoice compliance, and mobile carrier prefixes for Maxis, Celcom, DiGi & U Mobile.
Malaysia Phone Numbers: Complete Format, Validation & E.164 Guide (2025)
Learn how to format, validate, and implement Malaysian phone numbers in your applications. This guide covers everything from MCMC regulations to E.164 conversion – essential for building web applications, managing customer databases, and developing telecommunications platforms. Whether you're implementing SMS messaging systems, WhatsApp integrations, or ensuring IRBM e-invoice compliance, this guide provides the validation rules and code examples you need.
Understanding Malaysian Phone Number Structure
The Malaysian Communications and Multimedia Commission (MCMC) regulates Malaysia's phone number system, which adheres to international standards while incorporating unique regional variations. Here's the structure:
- Country Code: +60 (Required for international calls and E.164 format)
- National Prefix: 0 (Used for domestic calls within Malaysia)
- Area Code/Mobile Prefix: Distinguishes between fixed lines, mobile carriers (Maxis, Celcom, DiGi, U Mobile), and special services
- Subscriber Number: The unique identifier for a specific phone line
What Are the Malaysian Phone Number Formats and Validation Rules?
1. How to Validate Fixed Line Numbers in Malaysia
- Format:
0X-XXXX XXXX(X represents digits 3–9) - Example:
03-87654321(Kuala Lumpur landline) - Validation Regex:
^0[3-9]-\d{7,8}$(Accounts for both 7 and 8 digit subscriber numbers after the area code, accommodating variations across regions. Enforces the hyphen.) - Area Codes: Geographically assigned. In Peninsular Malaysia, area codes are one digit (3, 4, 5, 6, 7, 9), while East Malaysia (Sabah and Sarawak) uses two-digit area codes (e.g.,
82for Kuching,88for Kota Kinabalu). For example,03serves Kuala Lumpur, Putrajaya, and parts of Selangor. - Subscriber Number Length: Landline subscriber numbers are 8 digits in area code 3 (Kuala Lumpur, Selangor, Putrajaya), 7 digits in other Peninsular Malaysia areas, and 6 digits in East Malaysia.
- Implementation Notes: Store the full national number, including the leading
0, for domestic use. When formatting for display, maintain the hyphen between the area code and subscriber number.
Complete Area Code Reference Table
According to MCMC regulations, Malaysian area codes follow this structure:
| Area Code | Region/State | Subscriber Digits | Example |
|---|---|---|---|
| 03 | Selangor, Kuala Lumpur, Putrajaya, Genting Highlands (Pahang) | 8 | 03-2xxx xxxx |
| 04 | Perlis, Kedah, Penang, Pengkalan Hulu (Perak) | 7 | 04-2xx xxxx |
| 05 | Perak, Cameron Highlands (Pahang), Hulu Bernam (Selangor) | 7 | 05-2xx xxxx |
| 06 | Negeri Sembilan, Malacca, Muar/Tangkak/Batu Anam (Johor) | 7 | 06-2xx xxxx |
| 07 | Johor, Gemas (Negeri Sembilan) | 7 | 07-2xx xxxx |
| 09 | Pahang, Terengganu, Kelantan | 7 | 09-2xx xxxx |
| 082 | Sarawak (Kuching, Samarahan, Serian) | 6 | 082-2x xxxx |
| 083 | Sarawak (Sri Aman, Betong) | 6 | 083-2x xxxx |
| 084 | Sarawak (Sibu, Sarikei, Mukah, Kapit) | 6 | 084-2x xxxx |
| 085 | Sarawak (Miri, Limbang, Lawas) | 6 | 085-2x xxxx |
| 086 | Sarawak (Bintulu, Belaga) | 6 | 086-2x xxxx |
| 087 | Sabah (Labuan, Interior Division) | 6 | 087-2x xxxx |
| 088 | Sabah (Kota Kinabalu, Kudat) | 6 | 088-2x xxxx |
| 089 | Sabah (Lahad Datu, Sandakan, Tawau) | 6 | 089-2x xxxx |
Note: Area code 02 was formerly used for direct dialing to Singapore but was discontinued in May–July 2017. Area code 080 is reserved for domestic access from East Malaysia to Brunei. Area code 081 is reserved for future use.
Fixed Line Validation Code Examples
JavaScript:
function validateMalaysianLandline(number) {
// Remove spaces and validate format
const cleaned = number.replace(/\s+/g, '');
// Area code 3: 10 digits total (0 + 1 digit area code + 8 digits)
const area3Regex = /^03-?\d{8}$/;
// Other Peninsular Malaysia: 9 digits total (0 + 1 digit area code + 7 digits)
const peninsularRegex = /^0[4-79]-?\d{7}$/;
// East Malaysia: 9 digits total (0 + 2 digit area code + 6 digits)
const eastMalaysiaRegex = /^08[2-9]-?\d{6}$/;
return area3Regex.test(cleaned) ||
peninsularRegex.test(cleaned) ||
eastMalaysiaRegex.test(cleaned);
}
// Examples
console.log(validateMalaysianLandline("03-87654321")); // true (KL)
console.log(validateMalaysianLandline("04-2345678")); // true (Penang)
console.log(validateMalaysianLandline("082-234567")); // true (Kuching)Python:
import re
def validate_malaysian_landline(number):
"""Validate Malaysian landline numbers according to MCMC format."""
# Remove spaces
cleaned = number.replace(" ", "")
# Area code 3: 10 digits total
area3_pattern = r'^03-?\d{8}$'
# Other Peninsular Malaysia: 9 digits total
peninsular_pattern = r'^0[4-79]-?\d{7}$'
# East Malaysia: 9 digits total
east_malaysia_pattern = r'^08[2-9]-?\d{6}$'
return bool(re.match(area3_pattern, cleaned) or
re.match(peninsular_pattern, cleaned) or
re.match(east_malaysia_pattern, cleaned))
# Examples
print(validate_malaysian_landline("03-87654321")) # True (KL)
print(validate_malaysian_landline("04-2345678")) # True (Penang)
print(validate_malaysian_landline("082-234567")) # True (Kuching)PHP:
function validateMalaysianLandline($number) {
// Remove spaces
$cleaned = str_replace(' ', '', $number);
// Area code 3: 10 digits total
$area3Pattern = '/^03-?\d{8}$/';
// Other Peninsular Malaysia: 9 digits total
$peninsularPattern = '/^0[4-79]-?\d{7}$/';
// East Malaysia: 9 digits total
$eastMalaysiaPattern = '/^08[2-9]-?\d{6}$/';
return preg_match($area3Pattern, $cleaned) ||
preg_match($peninsularPattern, $cleaned) ||
preg_match($eastMalaysiaPattern, $cleaned);
}
// Examples
var_dump(validateMalaysianLandline("03-87654321")); // true (KL)
var_dump(validateMalaysianLandline("04-2345678")); // true (Penang)
var_dump(validateMalaysianLandline("082-234567")); // true (Kuching)2. How to Validate Malaysian Mobile Numbers
- Format:
01X-XXXX XXXX(X represents digits 0–9) - Example:
012-3456789(7-digit subscriber number),011-23456789(8-digit subscriber number) - Subscriber Number Length: Numbers with prefixes 011 and 015 have 8-digit subscriber numbers (11 digits total including leading 0), while all other mobile prefixes have 7-digit subscriber numbers (10 digits total including leading 0).
- Validation Regex:
^01[0-9]-\d{7,8}$(Accounts for 7 or 8 digit subscriber numbers following the 01X prefix. Note that some MVNOs might use slightly different formats.) - Mobile Number Portability (MNP): Implemented in Malaysia on October 1, 2008. Since MNP is active, the prefix no longer definitively identifies the carrier. However, as of 2025, Malaysia's MNP service has a high rejection rate (over 50% of porting requests are rejected), compared to best practice services which have rejection rates below 10%. Consider using a carrier lookup service for accurate routing if necessary.
- Prefix Allocation: While prefixes are associated with operators, the ranges can be complex. Refer to the MCMC or operator websites for the most up-to-date allocations. The detailed breakdown below provides current prefix ranges.
Mobile Prefix-to-Carrier Mapping Table
According to MCMC data, the following table shows the current mobile prefix allocations (as of 2025). Note that due to MNP, these prefixes indicate the original carrier only:
| Prefix | Digits | Operator/MVNO | Examples |
|---|---|---|---|
| 010 | 7 | Celcom, XOX, UniFi Mobile, Tune Talk | 010-2xxxxxx, 010-36xxxxx |
| 011 | 8 | UniFi Mobile, redONE, U Mobile, Maxis, XOX, Celcom, Tune Talk, DiGi, Yes 4G, Telekom Malaysia, Altel, BuzzME, Friendi | 011-100xxxxx to 011-605xxxxx |
| 012 | 7 | Maxis | 012-2xxxxxx to 012-9xxxxxx |
| 013 | 7 | Celcom | 013-2xxxxxx to 013-9xxxxxx |
| 014 | 7 | Maxis, DiGi, Tune Talk, Celcom | 014-2xxxxxx to 014-9xxxxxx |
| 015 | 8 | Onesmart Mobile, BluePack Network, B&E Wireless, Telekom Malaysia (TSoIP), Time Fibre, RedTone, Y-Max, Webe, Maxis, OCE, DiGi (data only), Celcom (data only) | 015-1xxxxxxx to 015-9xxxxxxx |
| 016 | 7 | DiGi | 016-2xxxxxx to 016-9xxxxxx |
| 017 | 7 | Maxis | 017-2xxxxxx to 017-9xxxxxx |
| 018 | 7 | U Mobile, Yes 4G | 018-12xxxxx, 018-2xxxxxx |
| 019 | 7 | Celcom | 019-2xxxxxx to 019-9xxxxxx |
Key Carriers:
- Celcom: 010, 013, 019, and shared ranges in 011, 014, 015
- Maxis: 012, 017, and shared ranges in 011, 014, 015
- DiGi: 016, and shared ranges in 011, 014, 015
- U Mobile: 018, and shared ranges in 011
- Yes 4G: 018, and shared ranges in 011
- UniFi Mobile: 010, and shared ranges in 011
- Tune Talk: 010, and shared ranges in 011, 014
Mobile Number Validation Code Examples
JavaScript:
function validateMalaysianMobile(number) {
// Remove spaces and hyphens
const cleaned = number.replace(/[\s-]/g, '');
// 011 and 015: 11 digits (including leading 0)
const long11Regex = /^0(11|15)\d{8}$/;
// All other 01X prefixes: 10 digits (including leading 0)
const standard10Regex = /^01[02-46-9]\d{7}$/;
return long11Regex.test(cleaned) || standard10Regex.test(cleaned);
}
// Examples
console.log(validateMalaysianMobile("012-3456789")); // true (Maxis, 10 digits)
console.log(validateMalaysianMobile("011-12345678")); // true (U Mobile, 11 digits)
console.log(validateMalaysianMobile("016-7654321")); // true (DiGi, 10 digits)
console.log(validateMalaysianMobile("015-98765432")); // true (VoIP, 11 digits)Python:
import re
def validate_malaysian_mobile(number):
"""Validate Malaysian mobile numbers with proper length handling."""
# Remove spaces and hyphens
cleaned = number.replace(" ", "").replace("-", "")
# 011 and 015: 11 digits total
long_pattern = r'^0(11|15)\d{8}$'
# All other 01X prefixes: 10 digits total
standard_pattern = r'^01[02-46-9]\d{7}$'
return bool(re.match(long_pattern, cleaned) or
re.match(standard_pattern, cleaned))
# Examples
print(validate_malaysian_mobile("012-3456789")) # True (Maxis, 10 digits)
print(validate_malaysian_mobile("011-12345678")) # True (U Mobile, 11 digits)
print(validate_malaysian_mobile("016-7654321")) # True (DiGi, 10 digits)
print(validate_malaysian_mobile("015-98765432")) # True (VoIP, 11 digits)PHP:
function validateMalaysianMobile($number) {
// Remove spaces and hyphens
$cleaned = str_replace([' ', '-'], '', $number);
// 011 and 015: 11 digits total
$longPattern = '/^0(11|15)\d{8}$/';
// All other 01X prefixes: 10 digits total
$standardPattern = '/^01[02-46-9]\d{7}$/';
return preg_match($longPattern, $cleaned) ||
preg_match($standardPattern, $cleaned);
}
// Examples
var_dump(validateMalaysianMobile("012-3456789")); // true (Maxis, 10 digits)
var_dump(validateMalaysianMobile("011-12345678")); // true (U Mobile, 11 digits)
var_dump(validateMalaysianMobile("016-7654321")); // true (DiGi, 10 digits)
var_dump(validateMalaysianMobile("015-98765432")); // true (VoIP, 11 digits)Java:
import java.util.regex.Pattern;
public class MalaysianPhoneValidator {
private static final Pattern LONG_PATTERN = Pattern.compile("^0(11|15)\\d{8}$");
private static final Pattern STANDARD_PATTERN = Pattern.compile("^01[02-46-9]\\d{7}$");
public static boolean validateMalaysianMobile(String number) {
// Remove spaces and hyphens
String cleaned = number.replaceAll("[\\s-]", "");
return LONG_PATTERN.matcher(cleaned).matches() ||
STANDARD_PATTERN.matcher(cleaned).matches();
}
public static void main(String[] args) {
System.out.println(validateMalaysianMobile("012-3456789")); // true
System.out.println(validateMalaysianMobile("011-12345678")); // true
System.out.println(validateMalaysianMobile("016-7654321")); // true
}
}3. What Are Malaysia's Special Service Numbers?
- Toll-Free:
1800-XX-XXXX(7 digits after 1800) - Premium Rate: Multiple prefixes exist for premium services:
1-300-XX-XXXX: Local rate telephone numbers1-700-XX-XXXX: Personal numbering service1-900-XX-XXXX: Multimedia service numbers600-XX-XXXX: Audiotext hosting and premium-rate numbers
- Emergency Services:
999(for police, fire, and ambulance) and112(international emergency number) - Short Codes: Various shortcodes exist for specific services (e.g., directory assistance, time announcements). These typically have 3–6 digits.
Comprehensive List of Special Service Numbers
According to MCMC regulations, the following special service numbers are available:
| Number/Prefix | Service | Cost |
|---|---|---|
| 999 | Malaysian General Emergency Service (Police, Fire, Ambulance) | FREE |
| 112 | International Emergency Number | FREE |
| 997 | National Scam Response Centre (NSRC) | FREE |
| 100 | General telephone services | Varies |
| 101 | Operator assistance (domestic calls) | Varies |
| 102 | Service assistance | Varies |
| 103 | Fixed telephone line directory assistance | Varies (RM1.50/call on some networks) |
| 104 | Telegram services | Varies |
| 1051 | Time announcement | RM0.10–1.50/call depending on carrier |
| 1066 | Earthquakes and Tsunami Alert Centre | Varies |
| 108 | Operator assistance (international calls) | Varies |
| 15454 | Tenaga Nasional Berhad (electricity fault reporting) | RM0.15/30 sec (Celcom), RM0.30/min (Digi) |
| 15999 | Talian Kasih (emotional support & counseling) | FREE on most networks |
| 1800-XX-XXXX | Toll-free numbers | FREE from landlines, local rate from mobile |
| 1300-XX-XXXX | Local rate telephone numbers | RM0.30–0.36/min |
| 1700-XX-XXXX | Personal numbering service | RM0.60/min |
| 1900-XX-XXXX | Multimedia service numbers | Premium rate |
| 600-XX-XXXX | Audiotext hosting and premium-rate | Variable rates based on prefix (600-81 to 600-86) |
Premium Rate 600 Numbers Pricing (Peak/Off-Peak):
- 600-81: RM0.13/min (peak), RM0.09–0.20/min (off-peak)
- 600-82: RM0.39/min (peak), RM0.20/min (off-peak)
- 600-83: RM0.78/min (peak), RM0.39/min (off-peak)
- 600-84: RM1.30/min (peak), RM0.65/min (off-peak)
- 600-85: RM1.95/min (peak), RM0.98/min (off-peak)
- 600-86: RM1.95–3.90/min (peak), RM0.98–1.95/min (off-peak)
Source: CelcomDigi Special Rates
Special Number Validation Code Examples
JavaScript:
function validateMalaysianSpecialNumber(number) {
const cleaned = number.replace(/[\s-]/g, '');
// Emergency services
if (/^(999|112|997)$/.test(cleaned)) return { valid: true, type: 'emergency' };
// Toll-free
if (/^1800\d{6}$/.test(cleaned)) return { valid: true, type: 'toll-free' };
// Local rate
if (/^1300\d{6}$/.test(cleaned)) return { valid: true, type: 'local-rate' };
// Personal numbering
if (/^1700\d{6}$/.test(cleaned)) return { valid: true, type: 'personal' };
// Multimedia service
if (/^1900\d{6}$/.test(cleaned)) return { valid: true, type: 'multimedia' };
// Premium rate audiotext
if (/^600[8][1-6]\d{4}$/.test(cleaned)) return { valid: true, type: 'premium' };
// Short codes (3-6 digits)
if (/^(100|10[1-8]|1051|1066|15454|15999)$/.test(cleaned)) return { valid: true, type: 'service' };
return { valid: false, type: null };
}
// Examples
console.log(validateMalaysianSpecialNumber("999")); // { valid: true, type: 'emergency' }
console.log(validateMalaysianSpecialNumber("1800123456")); // { valid: true, type: 'toll-free' }
console.log(validateMalaysianSpecialNumber("1300654321")); // { valid: true, type: 'local-rate' }Python:
import re
def validate_malaysian_special_number(number):
"""Validate Malaysian special service numbers."""
cleaned = number.replace(" ", "").replace("-", "")
# Emergency services
if re.match(r'^(999|112|997)$', cleaned):
return {'valid': True, 'type': 'emergency'}
# Toll-free
if re.match(r'^1800\d{6}$', cleaned):
return {'valid': True, 'type': 'toll-free'}
# Local rate
if re.match(r'^1300\d{6}$', cleaned):
return {'valid': True, 'type': 'local-rate'}
# Personal numbering
if re.match(r'^1700\d{6}$', cleaned):
return {'valid': True, 'type': 'personal'}
# Multimedia service
if re.match(r'^1900\d{6}$', cleaned):
return {'valid': True, 'type': 'multimedia'}
# Premium rate audiotext
if re.match(r'^600[8][1-6]\d{4}$', cleaned):
return {'valid': True, 'type': 'premium'}
# Short codes
if re.match(r'^(100|10[1-8]|1051|1066|15454|15999)$', cleaned):
return {'valid': True, 'type': 'service'}
return {'valid': False, 'type': None}
# Examples
print(validate_malaysian_special_number("999")) # {'valid': True, 'type': 'emergency'}
print(validate_malaysian_special_number("1800123456")) # {'valid': True, 'type': 'toll-free'}4. How to Convert Malaysian Numbers to E.164 Format
- Format:
+60XXXXXXXXXX(Remove the leading0and any hyphens or spaces) - Example:
+60387654321 - Implementation: Store numbers in E.164 format for database storage and international compatibility. Convert numbers to the local format for display purposes.
- IRBM e-Invoice Compliance: As of April 12, 2025, Malaysia's Inland Revenue Board (IRBM) requires all phone numbers in e-invoices to follow E.164 format. This means phone numbers must start with
+, include the country code+60, and contain no spaces, hyphens, or parentheses (e.g.,+60123456789not012-345 6789).
How to Implement Malaysian Phone Number Validation in Your Application
function toE164(malaysianNumber) {
// Remove spaces, hyphens, and leading zero
const cleaned = malaysianNumber.replace(/[\s-]/g, '').replace(/^0/, '');
return `+60${cleaned}`;
}
function fromE164(e164Number) {
// Extract the national number
const nationalNumber = e164Number.replace(/^\+60/, '');
// Mobile numbers (01X prefix)
if (nationalNumber.startsWith('1')) {
const prefix = nationalNumber.slice(0, 2);
// 011 and 015 have 8-digit subscriber numbers
if (prefix === '11' || prefix === '15') {
return `0${nationalNumber.slice(0, 2)}-${nationalNumber.slice(2)}`;
}
// Other 01X prefixes have 7-digit subscriber numbers
return `0${nationalNumber.slice(0, 2)}-${nationalNumber.slice(2)}`;
}
// Landline numbers
else if (nationalNumber.startsWith('3')) {
// Area code 3 (Kuala Lumpur, Selangor, Putrajaya) has 8-digit subscriber numbers
return `0${nationalNumber.slice(0, 1)}-${nationalNumber.slice(1)}`;
}
else if (nationalNumber.startsWith('8')) {
// East Malaysia (two-digit area codes, 6-digit subscriber numbers)
return `0${nationalNumber.slice(0, 2)}-${nationalNumber.slice(2)}`;
}
else {
// Other Peninsular Malaysia area codes (7-digit subscriber numbers)
return `0${nationalNumber.slice(0, 1)}-${nationalNumber.slice(1)}`;
}
}Validation Best Practices
- Regex Validation: Use regex patterns to enforce the correct format.
- Length Checks: Verify the number of digits after removing formatting characters.
- Area Code/Prefix Validation: Cross-reference area codes and prefixes against official MCMC lists.
- Carrier Lookup (for Mobile): If precise routing is required, integrate a carrier lookup API.
- Input Sanitization: Always strip spaces, hyphens, and other formatting before validation to handle user input variations.
- Error Handling: Provide clear error messages indicating which part of the phone number is invalid (e.g., "Invalid area code" vs. "Invalid number length").
- Security Considerations:
- Never expose phone numbers in URLs or logs without proper encryption
- Implement rate limiting on validation endpoints to prevent enumeration attacks
- Use HTTPS for all API calls involving phone number data
- Consider implementing phone number verification via SMS OTP before allowing account creation or sensitive operations
- Hash or tokenize phone numbers in non-production environments
- Apply proper access controls and audit logging for phone number lookups
How to Format Malaysian Phone Numbers for WhatsApp
When adding Malaysian contacts to WhatsApp or sending WhatsApp messages programmatically, use E.164 format without spaces or special characters:
- Correct WhatsApp Format:
+60123456789(for mobile012-3456789) - Alternative Format:
60123456789(WhatsApp accepts numbers with or without the+prefix) - Example for Business API: When using WhatsApp Business API or SMS API integrations, format all Malaysian numbers as
+60followed by the digits after the leading0.
WhatsApp Number Formatting Examples:
| Local Format | WhatsApp Format | Description |
|---|---|---|
| 012-3456789 | +60123456789 | Maxis mobile |
| 011-12345678 | +6011112345678 | U Mobile (8-digit subscriber) |
| 03-87654321 | +60387654321 | KL landline (works for WhatsApp calls) |
What Are the Best Practices for Storing and Displaying Malaysian Phone Numbers?
- Storage: Store numbers in E.164 format for consistency and efficient querying. You can store the original format as a separate field if needed.
- Display: Format numbers according to local conventions for user-friendliness. Use international format when appropriate (e.g., for international contacts).
Database Schema Recommendations
When storing Malaysian phone numbers in a database, consider this schema:
CREATE TABLE contacts (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
phone_e164 VARCHAR(15) NOT NULL, -- E.164 format: +60XXXXXXXXXX
phone_display VARCHAR(20), -- Local format: 0XX-XXXXXXXX
phone_type ENUM('mobile', 'landline', 'toll-free', 'premium', 'other'),
carrier VARCHAR(50), -- Original carrier (pre-MNP)
country_code CHAR(2) DEFAULT 'MY',
verified_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_phone_e164 (phone_e164),
INDEX idx_phone_type (phone_type)
);Key considerations:
- Use
phone_e164as the primary searchable field with an index - Store
phone_displayfor presenting to users in local format - Include
phone_typefor routing and business logic - Track
verified_atto know which numbers have been confirmed via SMS OTP - Use VARCHAR(15) for E.164 as the maximum length is 15 digits per ITU-T E.164 standard
Data Migration from Legacy Formats
If migrating from legacy systems with various formats:
def migrate_malaysian_phone_number(legacy_number):
"""Convert legacy phone number formats to E.164."""
import re
# Remove all non-digit characters except +
cleaned = re.sub(r'[^\d+]', '', legacy_number)
# Already in E.164 format
if cleaned.startswith('+60'):
return cleaned
# Has country code but no +
if cleaned.startswith('60'):
return '+' + cleaned
# Local format with leading 0
if cleaned.startswith('0') and len(cleaned) >= 9:
return '+60' + cleaned[1:]
# No leading 0 (malformed)
if len(cleaned) >= 8 and not cleaned.startswith('0'):
return '+60' + cleaned
# Invalid format
raise ValueError(f"Cannot parse phone number: {legacy_number}")
# Usage
legacy_numbers = ["03-87654321", "60387654321", "012-3456789", "0166543210"]
for num in legacy_numbers:
try:
print(f"{num} -> {migrate_malaysian_phone_number(num)}")
except ValueError as e:
print(f"Error: {e}")What Is Malaysia's 5G Network Coverage in 2025?
Malaysia transitioned from a single wholesale 5G network to a dual 5G network model (effective December 31, 2024, per Ministerial Direction No. 4 of 2024). Digital Nasional Berhad (DNB), wholly owned by the Minister of Finance, operates the first 5G network, while U Mobile operates the second 5G network.
5G Advanced Technology: In February 2025, DNB and Ericsson launched 5G Advanced technology on DNB's network, leveraging AI to enhance user experience with ultra-low latency and high throughput. DNB delivers a minimum download speed of 100 Mbps across the network, with an average 5G speed of 240 Mbps.
Coverage Targets: The state government, in collaboration with MCMC, is working to achieve 100% 5G network coverage across Selangor by 2025. 4G coverage is extensive, reaching over 95% of populated areas, including rural regions.
Find coverage maps and speed test data from resources like nPerf, DNB's interactive coverage map (digital-nasional.com.my/interactive-map), and operator websites (e.g., Maxis, CelcomDigi, U Mobile). This information is valuable for developers building location-aware applications or services that rely on network connectivity.
Frequently Asked Questions About Malaysian Phone Numbers
What is the country code for Malaysia?
Malaysia's country code is +60. Add this prefix before the national number when calling from outside Malaysia, and remove the leading 0 from the domestic number.
How many digits are in a Malaysian mobile number?
Malaysian mobile numbers have either 10 or 11 digits total (including the leading 0). Prefixes 011 and 015 have 8-digit subscriber numbers (11 digits total), while all other mobile prefixes have 7-digit subscriber numbers (10 digits total).
How do I format a Malaysia phone number for WhatsApp?
Format Malaysian numbers in E.164 format for WhatsApp: +60123456789 (remove the leading 0 and add +60). WhatsApp also accepts numbers without the + prefix, e.g., 60123456789.
What is the emergency number in Malaysia?
The emergency number in Malaysia is 999, which connects you to police, fire, and ambulance services. You can also dial 112, the international emergency number.
How do I validate a Malaysian phone number?
Use regex patterns to validate format: ^0[3-9]-\d{7,8}$ for landlines and ^01[0-9]-\d{7,8}$ for mobile numbers. Verify area codes against official MCMC lists and check digit length after removing formatting characters. For production applications, consider using libraries like Python's phonenumbers or validation APIs.
What is Mobile Number Portability (MNP) in Malaysia?
MNP allows customers to switch mobile providers while keeping their phone number. Implemented on October 1, 2008, Malaysia's MNP service currently has a high rejection rate (over 50%), significantly above the global best practice of below 10%.
What are the main mobile carriers in Malaysia?
The main mobile carriers are Maxis (prefixes 012, 017), Celcom (010, 013, 019), DiGi (016), and U Mobile (018). However, due to Mobile Number Portability, prefixes no longer guarantee which carrier currently serves a number.
Which area code is used for Kuala Lumpur?
Kuala Lumpur uses area code 03, which also covers Putrajaya and parts of Selangor. Landlines in this area have 8-digit subscriber numbers.
What format should I use to store Malaysian phone numbers in a database?
Store phone numbers in E.164 format (+60XXXXXXXXXX) for consistency, international compatibility, and efficient querying. You can store the original format as a separate field if needed for display purposes.
Are toll-free numbers really free in Malaysia?
1800 numbers are free when called from landlines but are charged at local rates when called from mobile phones. Check with your carrier for specific rates.
What is the IRBM e-invoice phone number requirement?
As of April 12, 2025, Malaysia's IRBM requires all phone numbers in e-invoices to be in strict E.164 format: starting with +, followed by country code +60, with no spaces, hyphens, or parentheses (e.g., +60123456789).
What validation libraries support Malaysian phone numbers?
Several libraries support Malaysian phone numbers including Google's libphonenumber (available for Java, JavaScript, Python, C++), and commercial APIs like Abstract's Phone Validation API and Twilio Lookup.
Keeping Up-to-Date
The telecommunications landscape is constantly evolving. Refer to the MCMC website and the official Numbering and Electronic Addressing Plan (NEAP) for the latest regulations and numbering plan updates. The NEAP is published by MCMC and covers telecommunications numbering, including sub-section 13 on Domain Names.
Key Resources:
- MCMC Official Site: mcmc.gov.my – Primary regulatory authority
- NEAP Documentation: Available at mynic.my/neap
- Operator Websites: Check Maxis, CelcomDigi, DiGi, U Mobile, and other carriers for prefix allocations and service updates
- Wikipedia Reference: Telephone numbers in Malaysia – Community-maintained resource with historical context
Change Management Best Practices:
- Monitor MCMC announcements for new prefix allocations or format changes
- Implement a configurable validation system that can be updated without code deployment
- Maintain a separate configuration file or database table for area codes and prefixes
- Set up alerts for validation failures that may indicate new number formats
- Review and update validation rules quarterly to catch new MVNO prefixes
- Subscribe to MCMC's mailing list or RSS feeds for regulatory updates
- Test your validation logic against real-world numbers periodically